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ß)