develooper Front page | perl.perl6.language | Postings from March 2005

Re: How are types related to classes and roles?

Thread Previous | Thread Next
From:
Thomas Sandlaß
Date:
March 4, 2005 12:12
Subject:
Re: How are types related to classes and roles?
Message ID:
4228C11A.7030903@orthogon.com
HaloO Larry,

you wrote:
> One can view the auto-coercion as a form of MMD if you allow the
> autogeneration of any necessary coercion methods.  However, it's not
> exactly a coercion to Str or Int--it's more like promotion to a Scalar
> that is able to pretend it is either Str or Int.  Or you can view it
> as a kind of cached conversion.  The ~ operator doesn't demand the
> Str type--it only demands something which can fulfill the string role.

I don't understand which role roles play :)
Since they are not instanciable they are well suited to be interpreted
as (abstract) types in other languages or type generators.
A very interesting thing is that they can be arranged into a lattice
if any() and all() junctions on roles give their lubs and glbs.
So having e.g. two roles A and B

role A { ... }
role B { ... }

we get first the rhomb shaped Hasse Diagram:

                 A|B         lub (lowest upper bound)
                /   \
               /     \
              A   0   B
             / \     / \
            /   \   /   \
           /     A&B     \   glb (greatest lower bound)
          /  1  /   \  2  \
         /     /  3  \     \

In the cones below A and B respectively are classes that do A or B:

class X does A { ... }
class Y does B { ... }

The roles themself beeing the least member of these classes---uninstanciable "pure"
behaviour. The intersection type/role A&B is multiple inheritance (or is that
"roling"?):

class Z does A does B { ... }
class Z does A & B { ... }  # valid syntax?

The junctive classes in area 0 are special because they need to do special
stuff *between* A and B. The prime example for this is

class Scalar does Str | Int { ... }

This syntax can be seen as some kind of superclassing or superroling:
a Scalar can go where no plain Str or Int can go!
BTW, what does a class that is specified without a role?
I think it would do the lub of of roles: Any. Right?

The above assumes that type checking and MMD is on behave of roles
and that classes are used for single dispatched methods only. So an
implementor of Scalar has to do some extra work for the any-junctive
behaviour, like the multiroling implemention has to resolve potential
conflicts between composed roles. Unfortunately I have no clear idea
of what these extras are and to what extent they can be enforced by
the compiler.  Typically a class like Scalar mostly brings in coercions
and mixed multi methods, i.e. they are a bit less restricted in what multis
they are allowed to define---if of course Perl 6 is using implementation
side type checks at all.


> I think the best thing we can do here is to encourage a culture in
> which people recognize the fundamental difference between extending
> a base class and constraining a subtype, and learn to use composition
> and delegation where appropriate instead of inheritance.  That's why
> we've given different keywords to all those concepts.  It's a matter
> of giving people the mental tools to think straighter.

Does this toolset support F-bounded polymorphism? And how is its syntax?
To illustrate this question I've rephrased the examples and adjusted the
explainations from the Cecil Manual in Perl 6 below. The original can be
found at

http://www.cs.washington.edu/research/projects/cecil/www/Vortex-Three-Zero/doc-cecil-lang/cecil-spec-86.html

This subsection describes an example of advanced use of the Cecil type
system, F-bounded polymorphism. As we will see, no special support for
this powerful idiom is needed in the type system -- it is made
possible by allowing constraints to be recursive, whereby a type
variable can appear in its own bound.

For our first example, let us consider an abstract object ordered and
a binary method >. A binary method is a method that expects two
arguments of similar types; the > method can be applied, for example,
to two numbers or two strings, but not a string and a number. We would
like to define this method once, in the Ordered role, and have other
classes, such as Num and Str, inherit it. The simplest way to
achieve it seems to be as follows:

role Ordered
{
    multi method infix:«<=» ( Ordered $x, Ordered $y ) returns bool
    {
      ...
    }
    multi method infix:«>» ( Ordered $x, Ordered $y ) returns bool
    {
       return not $x <= $y
    }
}

class Num does Ordered { ... }
class Str does Ordered { ... }

This code, however, leads to an undesirable effect. Since > and <= are
defined for Ordered and Num and Str are its subclasses, we are
required to write implementations of <= to compare a num and a string,
which we may not want. To avoid mixing of subclasses of ordered, we
can apply F-bounded polymorphism as follows:

role Ordered[ type ::T where { T <= Ordered[T] } ]    # op '<=' defined for types?
role Ordered[ type ::T where { T does Ordered[T] } ]
role Ordered[ ::T does Ordered[T] ]  # operator 'does' allowed here?
role Ordered[ Ordered[::T] ::T ]
role Ordered[ Ordered[T] ::T ]   # too short, because T is not known before ::T?
{
    multi method infix:«<=» ( T $x, T $y ) returns bool
    {
      ...
    }
    multi method infix:«>» ( T $x, T $y ) returns bool
    {
       return not $x <= $y
    }
}

class Num does Ordered[Num] { ... }
class Str does Ordered[Str] { ... }

class Scalar does Ordered[Num|Str] { ... }  # Perl 6 actually has that

Now method > can be instantiated with Num for T (because the
instantiated constraint Num <= Ordered[Num] can be solved: there is a
corresponding declaration in the program) or with Str for T, but
cannot with Str|Num for T (which would be required in order to
compare a Num and a Str).

With this scheme, in addition to defining binary methods itself,
ordered and all its subtypes can inherit binary methods from other
objects, for example:

role Comparable[ type ::T where { T <= Comparable[T] } ]
role Comparable[ ::T does Comparable[T] ]
role Comparable[ Comparable[::T] ::T ]
role Comparable[ Comparable[T] ::T ]
{
    multi method infix:«==» ( T $x, T $y ) returns bool
    {
      ...
    }
    multi method infix:«!=» ( T $x, T $y ) returns bool
    {
       return not $x == $y
    }
}

role Ordered[ type ::T ] does Comparable[T]
{
    multi method infix:«<=» ( T $x, T $y ) returns bool
    {
      ...
    }
    multi method infix:«>» ( T $x, T $y ) returns bool
    {
       return not $x <= $y
    }
}

Moreover, Num can have subtypes, such as Int or Float, which can be
compared with each other, but not with Str or its subtypes:

class Int   is Num {...}
class Float is Num {...}
3 != 3.14  # legal


Sorry if this is too brain-dead!
-- 
TSa (Thomas Sandlaß)


Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About