HaloO, Ben Morrow wrote:
Isn't this just sugar for something like
Yes it is. My intent was to lighten the burden. I think we can agree that Ovid's problem can be solved by means of the current spec and some support syntax could be easily added.
What this doesn't fix is that some other code (outside the class) will be expecting C::x to have T1::x semantics, and some will be expecting it to have T2::x semantics. If these are contradictory, there is no way to write an x which works. That's where the 'hats' idea comes in, so you could write something like class C does T1 does T2 { method T1::x { ... } method T2::x { ... } } and have callers that thought they were getting a T1 call the appropriate override. However, there's still a problem with callers that know they have a C: which method do they get?
I have the following proposal to integrate the problem with the type system. We simply say that roles have an invocant slot in their type signature that is filled by the class they are composed into. That is 'class C does R' creates the type R[C:] which is distinct from R[A:] for 'class A does R'. These two are of course applicable where plain R is expected because this means R[Object:] and we have covariance in the invocant parameter. As a limiting case the role has type R[R:] that is an empty anonymous class with only the role composed. This can of course not be instanciated. Using that as a constraint e.g. in a signature or a container means that neither R[A:] nor R[C:] are applicable. However they can implement coercion routines C::R and A::R that convert the object and these are invoked when needed. So an extreme class might provide coercion routines to all its roles without loosing the identity of the object. And perhaps these might be generated automatically for easy cases. Consider the cartesian versus polar complex number example. Here one provides a role Complex and two classes Cartesian and Polar that do that role and implement conversion routines to each other. Then some optimized multi subs might be written that require Complex[Polar:] and Complex[Cartesian:]. Others just use Complex and are happy with both representations.
AFAICS the only real solution to this is something like COM, where you say 'I would like to talk to this object as though it were a T1 now'. Might it be possible to use the type system to make this less painful than it usually is?
The invocant slot of the role signature is sort of implied in the spec already! I also like this because a type in Perl 6 is then always written as SomeRole[SomeClass:]. Classes without explicit roles are Any[SomeClass:] and untyped is Any[Object:]. Note that a class C doing multiple roles spawns several types R1[C:], R2[C:], etc and the class name is a short form of their juxtaposition. So a typical CPAN module might provide a role together with classes that implement it in different ways and the users can nicely choose between them and add their own implementations. Users and such split modules can then use the roles and classes as bases for their own development. Note that this also allows more specific signatures like foo( Order[::T:] $x, Order[T:] $y ) which guarantees comparability of $x and $y without relying on mixed case MMD. Also we might have explicit specializations Order[Real:] that provides <, <=, > and >= in addition to before and after. Likewise for Order[Str:] which is of course not applicable to Order[Real:] without coercion of Str to Num which does Real. The default Rat is then just Rat[rat64:] for example. And the instanciating class might also be defaulted lexically. Essentially all types are then denominated in this form which uniquely identifies a role/class combination by means of the colon in brackets after the name. Regards TSa. -- "The unavoidable price of reliability is simplicity" -- C.A.R. Hoare "Simplicity does not precede complexity, but follows it." -- A.J. Perlis 1 + 2 + 3 + 4 + ... = -1/12 -- Srinivasa Ramanujan