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

Reply via email to