Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

class interface of roles

6 views
Skip to first unread message

TSa

unread,
Sep 19, 2006, 11:51:32 AM9/19/06
to perl6-l...@perl.org
HaloO,

After re-reading about the typing of mixins in
http://www.jot.fm/issues/issue_2004_11/column1
I wonder how the example would look like in Perl6.
Here is what I think it could look like:

role GenEqual
{
method equal( : GenEqual $ --> Bool ) {...}
}

role GenPointMixin
{
has Int $.x;
has Int $.y;
method equal( ::?CLASS GenEqual $self: ::?CLASS $p --> Bool )
{
return super.equal(p) and # <-- handwave
self.x == $p.x and self.y == $p.y;
}
}

class GenSquare does GenEqual does GenPointMixin
{
has Int $.side;
method equal ( : ::?CLASS $p --> Bool )
{
return self.side == $p.side;
}
}

The handwave part is the interface of the composed role to
the class it is composed into and the typing of this interface.
The article proposes to expand the mixin self type prior to the
class interface. The latter then poses type constraints onto the
class. Do roles work like that in Perl6? I mean would the approach
of the article of using two F-bounded quantifications (see the last
formular in section 8) be a valid type model for class composition?


Regards, TSa.
--

TSa

unread,
Sep 26, 2006, 7:03:10 AM9/26/06
to perl6-l...@perl.org
HaloO,

is this subject not of interest? I just wanted to start a
discussion about the class composition process and how a
role designer can require the class to provide an equal
method and then augment it to achieve the correct behavior.
Contrast that with the need to do the same in every class
that gets the equal method composed into if the role doesn't
have a superclass interface as described in the article.


Regards,
--

Sam Vilain

unread,
Oct 2, 2006, 12:51:54 AM10/2/06
to TSa, perl6-l...@perl.org

This will be the same as requiring that a class implements a method,
except the method's name is infix:<==>(::T $self: T $other) or some such.

Sam.

Brad Bowman

unread,
Oct 2, 2006, 5:16:59 AM10/2/06
to perl6-l...@perl.org
Sam Vilain wrote:

How does a Role require that the target class implement a method (or
do another Role)?

Does the "class GenSquare does GenEqual does GenPointMixin" line imply
an ordering of class composition? This would seem to be required for
the super.equal hand-wave to work but part of the Traits Paper goodness
came from avoiding an ordering. Composition is just order insensitive
flattening. Conflicts like the equal method in the OP have to be
explicitly resolved in the target class, either using aliases
or fully qualified names. So there's no super needed.

I would like a way to make one Role to require that the target class
"does" another abstract Role, is there already such a technique?

(I should confess that I haven't yet read the OP linked article),

Brad

Stevan Little

unread,
Oct 2, 2006, 10:19:02 AM10/2/06
to Brad Bowman, perl6-l...@perl.org
On 10/2/06, Brad Bowman <li...@bereft.net> wrote:
> Sam Vilain wrote:
> > TSa wrote:
> >> is this subject not of interest? I just wanted to start a
> >> discussion about the class composition process and how a
> >> role designer can require the class to provide an equal
> >> method and then augment it to achieve the correct behavior.
> >> Contrast that with the need to do the same in every class
> >> that gets the equal method composed into if the role doesn't
> >> have a superclass interface as described in the article.
> >>
> >
> > This will be the same as requiring that a class implements a method,
> > except the method's name is infix:<==>(::T $self: T $other) or some such.
>
> How does a Role require that the target class implement a method (or
> do another Role)?

IIRC, it simply needs to provide a method stub, like so:

method bar { ... }

This will tell the class composer that this method must be created
before everything is finished.

> Does the "class GenSquare does GenEqual does GenPointMixin" line imply
> an ordering of class composition? This would seem to be required for
> the super.equal hand-wave to work but part of the Traits Paper goodness
> came from avoiding an ordering. Composition is just order insensitive
> flattening. Conflicts like the equal method in the OP have to be
> explicitly resolved in the target class, either using aliases
> or fully qualified names. So there's no super needed.

The "super" in a Role should be late bound, so will have no relevance
when inside the role, but only make sense when composed into a class.
This is probably one of the more confusing points of roles I think.

As for how the example in the OP might work, I would suspect that
"super" would not be what we are looking for here, but instead a
variant of "next METHOD". However, even with that an ordering of some
kind is implied.

I suppose this is again where the different concepts of classes are
roles can get very sticky. I have always look at roles, once composed
into the class, as no longer needing to exist. In fact, if it weren't
for the idea of runtime role compostion and runtime role
introspection, I would say that roles themselves could be garbage
collected at the end of the compile time cycle.

> I would like a way to make one Role to require that the target class
> "does" another abstract Role, is there already such a technique?

I am not familiar with one, but I have had this need as well lately in
using Moose roles. We have a concept in Moose (stolen from the
Fortress language) where a particular role can exclude the use of
another role, but not the ability to require it, although I see no
reason why it couldn't be done.

- Stevan

Jonathan Lang

unread,
Oct 2, 2006, 11:23:44 AM10/2/06
to Brad Bowman, perl6language,
Brad Bowman wrote:
> Hi,
>
> Did you mean to go off list?

No, I didn't.

> Jonathan Lang wrote:


> > Brad Bowman wrote:
> >> Does the "class GenSquare does GenEqual does GenPointMixin" line imply
> >> an ordering of class composition?
> >

> > No. This was a conscious design decision: the order in which you
> > compose roles has no effect on the result.
>
> Great. That's what I want.


>
> >> I would like a way to make one Role to require that the target class
> >> "does" another abstract Role, is there already such a technique?
> >

> > What's wrong with just having the role compose the other abstract role
> > itself? That is, instead of "role Bar requires Baz; class Foo does
> > Bar does Baz", why not say "role Bar does Baz; class Foo does Bar"?
> >
>
> That would work, as long as you get a compile time error when
> Foo doesn't implement the Baz abstract interface.

...which is exactly what happens. Mind you, the compile-time error
won't report that Baz::method is unimplemented, or even that
Bar::method is unimplemented; it will report that Foo::method is
unimplemented. It's up to the programmer to figure out where
Foo::method came from, on the off chance that it matters.

> It's perhaps also less clear that the indirect Baz mixin must be
> implemented.

If Bar does Baz, you can read that as "Bar requires Baz to be
implemented, too."

There's a tendency, when dealing with traditional inheritance systems,
to think of the primary function of a superclass as being a supplier
of implementations for any classes that inherit from it. I submit
that this is the wrong way to think of roles: rather, a role is first
and foremost a source of interface requirements for whatever does that
role. If a role includes a method declaration, that should be read as
"anything that does this role must provide a method that matches this
one's name and signature." If a role does another role, that should
be read as "anything that does this role should conform to the
requirements of this other role as well." Any implementations that a
role provides should be viewed as _sample_ implementations, to be used
if and only if you can find no reason not to use them.

BTW, this includes attributes: if a role declares a public attribute,
this should be read as that role requiring an accessor method for that
attribute; if whatever does the role redefines the methods (including
the accessor method) such that none of them refer to the attribute,
the attribute should not be mixed in. If a role defines a private
attribute and then fails to define any methods that access that
attribute, the only way that that attribute should end up getting
mixed into something else is if whatever does the role that the
attribute is in provides the methods in question. In summary,
attributes and method bodies in roles should be taken as _suggestions_
- only the public method names and signatures should be viewed as
requirements.

> I guess any role could just declare some yada methods and leave it
> at that.

That too.

Bear in mind that when you compose a role into another role, you are
under no obligation to replace yada methods with defined ones. In
fact, it's even conceivable for you to replace a defined method with a
yada method if the default implementation from the other role isn't
suited to the current one. The only time that you're required to
replace yada methods with defined methods is when you compose into a
class.

--
Jonathan "Dataweaver" Lang

Jonathan Lang

unread,
Oct 2, 2006, 11:58:24 AM10/2/06
to Stevan Little, Brad Bowman, perl6-l...@perl.org
Stevan Little wrote:

> Brad Bowman wrote:
> > How does a Role require that the target class implement a method (or
> > do another Role)?
>
> IIRC, it simply needs to provide a method stub, like so:
>
> method bar { ... }
>
> This will tell the class composer that this method must be created
> before everything is finished.

Correct.

> I suppose this is again where the different concepts of classes are
> roles can get very sticky. I have always look at roles, once composed
> into the class, as no longer needing to exist. In fact, if it weren't
> for the idea of runtime role compostion and runtime role
> introspection, I would say that roles themselves could be garbage
> collected at the end of the compile time cycle.

Again, you've hit the nail on the head. To elaborate on this a little
bit, the only reason that perl needs to keep track of a role hierarchy
at all is for parameter matching purposes (if Foo does Bar and Bar
does Baz, Foo can be used if a signature asks for Baz).

> > I would like a way to make one Role to require that the target class
> > "does" another abstract Role, is there already such a technique?
>
> I am not familiar with one, but I have had this need as well lately in
> using Moose roles. We have a concept in Moose (stolen from the
> Fortress language) where a particular role can exclude the use of
> another role, but not the ability to require it, although I see no
> reason why it couldn't be done.

As I mentioned before, having role Bar require that Baz also be
composed is a simple matter of saying "role Bar does Baz".

This notion of exclusionary roles is an interesting one, though. I'd
like to hear about what kinds of situations would find this notion
useful; but for the moment, I'll take your word that such situations
exist and go from there.

I wonder if it would be worthwhile to extend the syntax of roles so
that you could prepend a "no" on any declarative line, resulting in a
compilation error any time something composing that role attempts to
include the feature in question. So, for instance, you might have

role Bar {
no method baz (Num, Str);
}

class Foo does Bar {
method baz (Num $n, Str $s) { ... } # compilation error: Bar
forbade this method!
}

or

role Bar no does Baz { # granted, the english grammar is all wrong...
}

class Foo does Bar does Baz { # compilation error: Bar forbade the
inclusion of Baz!
}

This is not the same as removing something that a composed role
brought in, which is a separate potentially useful notion. The former
is "Foo doesn't play well with Bar; so don't try to use them
together"; the latter is "Foo can do _almost_ everything Bar can, but
not quite." Mind you, if I ever see something to the effect of "Foo
does Bar except baz()" as valid syntax, I'll expect a query to the
effect of "Foo does Bar?" to answer to the negative. This would
include "can Foo be used when Bar is asked for?"

--
Jonathan "Dataweaver" Lang

Chromatic

unread,
Oct 2, 2006, 10:18:43 PM10/2/06
to perl6-l...@perl.org, Jonathan Lang
On Monday 02 October 2006 08:58, Jonathan Lang wrote:

> I wonder if it would be worthwhile to extend the syntax of roles so
> that you could prepend a "no" on any declarative line, resulting in a
> compilation error any time something composing that role attempts to
> include the feature in question.  So, for instance, you might have
>
>     role Bar {
>         no method baz (Num, Str);
>     }
>
>     class Foo does Bar {
>         method baz (Num $n, Str $s) { ... } # compilation error: Bar
> forbade this method!
>     }

This feels like the false-cognate problem waiting to creep back in.

-- c

Stevan Little

unread,
Oct 2, 2006, 10:50:16 PM10/2/06
to Jonathan Lang, Brad Bowman, perl6-l...@perl.org
On 10/2/06, Jonathan Lang <dataw...@gmail.com> wrote:
> This notion of exclusionary roles is an interesting one, though. I'd
> like to hear about what kinds of situations would find this notion
> useful; but for the moment, I'll take your word that such situations
> exist and go from there.

Well to be honest, I haven't found a real-world usage for it yet (at
least in my travels so far), but the Fortress example was this:

trait OrganicMolecule extends Molecule
excludes { InorganicMolecule }
end
trait InorganicMolecule extends Molecule end

And from that I could see that given a large enough set of roles you
would surely create roles which conflicted with one another on a
conceptual level rather then on a methods/attribute (i.e. - more
concrete) level.

- Stevan

TSa

unread,
Oct 5, 2006, 11:49:36 AM10/5/06
to perl6-l...@perl.org
HaloO,

Brad Bowman wrote:


> Sam Vilain wrote:
>> This will be the same as requiring that a class implements a
>> method, except the method's name is infix:<==>(::T $self: T $other)
>> or some such.

Sure. The point is, how does a role designer mix in the x and y
coordinate attributes *and* augment the notion of equality to
encompass these new attributes *without* shifting this burden onto
the class implementor!


> Does the "class GenSquare does GenEqual does GenPointMixin" line
> imply an ordering of class composition? This would seem to be
> required for the super.equal hand-wave to work but part of the Traits
> Paper goodness came from avoiding an ordering. Composition is just
> order insensitive flattening. Conflicts like the equal method in the
> OP have to be explicitly resolved in the target class, either using
> aliases or fully qualified names. So there's no super needed.

Hmm, my aim was more at the class composition process as such.
I envision a type bound calculation for all composed roles. This
bound then is available as super to all roles. Inter-role conflicts
are orthogonal to this. If the bound is fulfilled the order of
role composition doesn't matter. In the case of the equality checks
the different participants of the composition call each other and
use logical and to yield the final equality check. To the outside
world the equality method appears to be a single call on the type
of the objects created from the class. Note that it is type correct
in the sense that all participants are considered. My hope is that
this is achieved automatically as outcome of the composition process
and not by intervention of the class implementor.


> (I should confess that I haven't yet read the OP linked article),

To understand it you might actually need to read previous articles
in the series, too.


Regards,
--

TSa

unread,
Oct 6, 2006, 7:36:30 AM10/6/06
to perl6-l...@perl.org
HaloO,

Stevan Little wrote:
> As for how the example in the OP might work, I would suspect that
> "super" would not be what we are looking for here, but instead a
> variant of "next METHOD".

I'm not familiar with the next METHOD syntax. How does one get the
return value from it and how are parameters passed? Would the respective
line in the equal method then read:

return next METHOD($p) and self.x == $p.x and self.y == $p.y;

I think that a super keyword might be nice syntactic sugar for this.


> However, even with that an ordering of some
> kind is implied

The only ordering I see is that the class is "up" from the role's
perspective. When more then one role is combined and all require
the presence of an equal method I think the roles can be combined
in any order and the super refers to the class combined so far.
IOW, at any given time in the composition process there is a current
version of the class' method. The final outcome is a method WALK
or however this is called in composition order. Conceptually this
is method combination: seen from outside the class has just one
type correct method equal. Theoretical background can be found in
http://www.jot.fm/issues/issue_2004_01/column4


> I suppose this is again where the different concepts of classes are
> roles can get very sticky. I have always look at roles, once composed
> into the class, as no longer needing to exist. In fact, if it weren't
> for the idea of runtime role compostion and runtime role
> introspection, I would say that roles themselves could be garbage
> collected at the end of the compile time cycle.

I see that quite different: roles are the primary carrier of type
information! Dispatch depends on a partial ordering of roles. I
think all roles will form a type lattice that is available at
runtime for type checks. With parametric roles there will be dynamic
instanciations as needed.


Regards,
--

TSa

unread,
Oct 6, 2006, 11:07:03 AM10/6/06
to perl6-l...@perl.org
HaloO,

Stevan Little wrote:
> On 10/2/06, Jonathan Lang <dataw...@gmail.com> wrote:
>> This notion of exclusionary roles is an interesting one, though. I'd
>> like to hear about what kinds of situations would find this notion
>> useful; but for the moment, I'll take your word that such situations
>> exist and go from there.
>
> Well to be honest, I haven't found a real-world usage for it yet (at
> least in my travels so far), but the Fortress example was this:
>
> trait OrganicMolecule extends Molecule
> excludes { InorganicMolecule }
> end
> trait InorganicMolecule extends Molecule end

Wouldn't that be written in Perl6 the other way around?

role OrganicMolecule {...}
role InorganicMolecule {...}

role Molecule does OrganicMolecule ^ InorganicMolecule {...}

Which is a nice usage of the xor role combinator.


> And from that I could see that given a large enough set of roles you
> would surely create roles which conflicted with one another on a
> conceptual level rather then on a methods/attribute (i.e. - more
> concrete) level.

I don't abide to that. If roles are conceptually modelling the same
entity their vocabulary should conflict also. Well unless some
differing coding conventions accidentally produce non-conflicting
roles. The whole point of type systems relies on the fact that
concrete conflicts indicate conceptual ones!


Regards,
--

Jonathan Lang

unread,
Oct 6, 2006, 12:30:17 PM10/6/06
to TSa, perl6language,
TSa wrote:
> I'm not familiar with the next METHOD syntax.

It's simple: if a multi method says "next METHOD;" then execution of
the current method gets aborted, and the next MMD candidate is tried;
it uses the same parameters that the current method used, and it
returns its value to the current method's caller. In effect, "next
METHOD" is an aspect of MMD that allows an individual method to say
"I'm not the right guy for this job", and to punt to whoever's next in
line. If not for the possibility of side effects that occur before
the punt, one could pretend that the current method was never tried in
the first place.

> I see that quite different: roles are the primary carrier of type
> information! Dispatch depends on a partial ordering of roles. I
> think all roles will form a type lattice that is available at
> runtime for type checks.

True: the relationships between various roles and classes ("who does
what?") is needed for runtime type checking. However, the _contents_
of the roles are only important for composing classes and for the
occasional runtime introspection of a role. If roles are never
composed or inspected at runtime, the only details about them that
need to be kept are "who does what?" - and if all type-checking takes
place at compile-time, not even this is needed.

But now we're getting dangerously close to perl6internals territory...

--
Jonathan "Dataweaver" Lang

Stevan Little

unread,
Oct 7, 2006, 9:52:42 AM10/7/06
to TSa, perl6-l...@perl.org
On 10/6/06, TSa <Thomas....@barco.com> wrote:
> HaloO,
>
> Stevan Little wrote:
> > As for how the example in the OP might work, I would suspect that
> > "super" would not be what we are looking for here, but instead a
> > variant of "next METHOD".
>
> I'm not familiar with the next METHOD syntax. How does one get the
> return value from it and how are parameters passed? Would the respective
> line in the equal method then read:
>
> return next METHOD($p) and self.x == $p.x and self.y == $p.y;
>
> I think that a super keyword might be nice syntactic sugar for this.

I think super is not something we would want in Roles, it implies
ordering, which defeats the flattening aspect of Roles. IIRC the
syntax to call the next method with new args and a return value is
this:

return call($p) and self.x == $p.x and self.y == $p.y;

However, I am not sure I really like the look of that myself.

>
> > However, even with that an ordering of some
> > kind is implied
>
> The only ordering I see is that the class is "up" from the role's
> perspective.

But thats the whole problem, there is no "up" in roles, they are flattened.

> When more then one role is combined and all require
> the presence of an equal method I think the roles can be combined
> in any order and the super refers to the class combined so far.
> IOW, at any given time in the composition process there is a current
> version of the class' method. The final outcome is a method WALK
> or however this is called in composition order. Conceptually this
> is method combination: seen from outside the class has just one
> type correct method equal. Theoretical background can be found in
> http://www.jot.fm/issues/issue_2004_01/column4

I do not think method combination should be the default for role
composition, it would defeat the composeability of roles because you
would never have conflicts.

However, I can see the possibility of method combinations in roles
being some kind of special case. How that might look from a syntactic
perspective I have no idea.

> > I suppose this is again where the different concepts of classes are
> > roles can get very sticky. I have always look at roles, once composed
> > into the class, as no longer needing to exist. In fact, if it weren't
> > for the idea of runtime role compostion and runtime role
> > introspection, I would say that roles themselves could be garbage
> > collected at the end of the compile time cycle.
>
> I see that quite different: roles are the primary carrier of type
> information!

Well yes, they do seem to have taken on this role ;). However, roles
as originally envisioned in the Traits paper are not related to the
type system, but instead related to class/object system. In fact the
Trait paper gave it's examples in Smalltalk, which is not a strongly
typed language (unless you count the idea that *everything* is an
object and therefore that is their type).

I think we need to be careful in how we associate roles with the type
system and how we assocaite them with the object system. I worry that
they will end up with conflicting needs and responsibilities and roles
will end up being too complex to be truely useful.

> Dispatch depends on a partial ordering of roles.

Type based dispatch does (MMD), but class based method dispatch
doesn't need it at all.

The whole fact that dispatching requires roles to be partially ordered
actually tells me that maybe roles should not be so hinged to the type
system since roles are meant to be unordered.

Possiblely we should be seeing roles as a way of *implementing* the
types, and not as a core component of the type system itself?

I did some experimentation with this in Moose::Autobox, but that is
for Perl 5 so I am not sure how relevant it is here.

- Stevan

Stevan Little

unread,
Oct 7, 2006, 10:05:58 AM10/7/06
to TSa, perl6-l...@perl.org
On 10/6/06, TSa <Thomas....@barco.com> wrote:
> HaloO,
>
> Stevan Little wrote:
> > On 10/2/06, Jonathan Lang <dataw...@gmail.com> wrote:
> >> This notion of exclusionary roles is an interesting one, though. I'd
> >> like to hear about what kinds of situations would find this notion
> >> useful; but for the moment, I'll take your word that such situations
> >> exist and go from there.
> >
> > Well to be honest, I haven't found a real-world usage for it yet (at
> > least in my travels so far), but the Fortress example was this:
> >
> > trait OrganicMolecule extends Molecule
> > excludes { InorganicMolecule }
> > end
> > trait InorganicMolecule extends Molecule end
>
> Wouldn't that be written in Perl6 the other way around?
>
> role OrganicMolecule {...}
> role InorganicMolecule {...}
>
> role Molecule does OrganicMolecule ^ InorganicMolecule {...}
>
> Which is a nice usage of the xor role combinator.

Well, it does seem to accomplish a similar goal. However, in your
example there is nothing about the OrganicMolecule which will prevent
me from composing it with the InOrganicMolecule, which was the primary
goal of the Fortress example. In addition in the Fortress example the
Molecule role is not coupled to the Organic and Inorganic molecules,
in your example they are.

But IMHO this is just another example of TIMTOWTDI, because your
example achieves similar goals and would likely be a valid design
approach as well.

> > And from that I could see that given a large enough set of roles you
> > would surely create roles which conflicted with one another on a
> > conceptual level rather then on a methods/attribute (i.e. - more
> > concrete) level.
>
> I don't abide to that. If roles are conceptually modelling the same
> entity their vocabulary should conflict also. Well unless some
> differing coding conventions accidentally produce non-conflicting
> roles. The whole point of type systems relies on the fact that
> concrete conflicts indicate conceptual ones!

But part of the power of role composability is that the role itself
does not need to dictate what class it is composed into. So conceptual
conflicts cannot be determined until compostion actually occurs, and
conflicts between two conceptually conflicting roles cannot be
detected until composition time either. And of course there is nothing
to say that two conceptually conflicting roles have a concrete
conflict either (either between methods or attributes).

I think that maybe we need to seperate the concept of roles as types
and roles as partial classes, they seem to me to be in conflict with
one another. And even they are not in conflict with one another, I
worry they will bloat the complexity of roles usage.

My experiences thus far with roles in Moose have been that they can be
a really powerful means of reuse. I point you towards Yuval Kogman's
latest work on Class::Workflow, which is basically a loose set of
roles which can be composed into a highly customizable workflow
system. This is where I see the real power of roles coming into play.

- Stevan

Jonathan Lang

unread,
Oct 7, 2006, 11:04:46 AM10/7/06
to Stevan Little, TSa, perl6-l...@perl.org
TSa wrote:
> Dispatch depends on a partial ordering of roles.

Could someone please give me an example to illustrate what is meant by
"partial ordering" here?

--
Jonathan "Dataweaver" Lang

Matt Fowles

unread,
Oct 8, 2006, 9:14:59 PM10/8/06
to Jonathan Lang, Stevan Little, TSa, perl6-l...@perl.org
Jonathan~

On 10/7/06, Jonathan Lang <dataw...@gmail.com> wrote:
> TSa wrote:
> > Dispatch depends on a partial ordering of roles.
>
> Could someone please give me an example to illustrate what is meant by
> "partial ordering" here?

Sets demonstrate partial ordering. Let < denote the subset relation ship.

If A < B and B < C, then A < C for any A, B, and C.
However, it is not necessarily the case that A < B, or B < A, or B ==
A for any particular A and B.

Thus transitivity is preserved, but there is not a guarantee of
comparability between elements.

http://en.wikipedia.org/wiki/Partial_ordering

Matt
--
"Computer Science is merely the post-Turing Decline of Formal Systems Theory."
-Stan Kelly-Bootle, The Devil's DP Dictionary

TSa

unread,
Oct 9, 2006, 6:24:25 AM10/9/06
to perl6-l...@perl.org
HaloO,

Stevan Little wrote:
> I think that maybe we need to seperate the concept of roles as types
> and roles as partial classes, they seem to me to be in conflict with
> one another. And even they are not in conflict with one another, I
> worry they will bloat the complexity of roles usage.

The bloat aside I believe it is essential to have roles as the key
players of the type system. I propose to handle the typeish aspect of
roles as described in the paper I linked to: there should be a trait
'is augmented' that is applicable to a role and to methods in a role.
In such a method a call to next METHOD should invoke the class's method.
Alternatively we could make the method combination behavior the default
and have a class method trait 'is disambig' or 'is override' for the
case where the class needs to have the final word.

Note that the superclass interface of roles should be mostly inferred
from the usage of next METHOD. As such it is a useful guidance for
error reports in the class composition process.


> My experiences thus far with roles in Moose have been that they can be
> a really powerful means of reuse. I point you towards Yuval Kogman's
> latest work on Class::Workflow, which is basically a loose set of
> roles which can be composed into a highly customizable workflow
> system. This is where I see the real power of roles coming into play.

Is this a set of free mixins or are they dependent on the class to
provide a certain interface to fully achieve the means of the roles?
I also consider roles a powerful tool but I believe that the type
system should play a role in the composition process that goes beyond
simple checking of name clashes.


Regards,
--

TSa

unread,
Oct 9, 2006, 8:20:01 AM10/9/06
to perl6-l...@perl.org
HaloO,

Jonathan Lang wrote:
> TSa wrote:
> > Dispatch depends on a partial ordering of roles.
>
> Could someone please give me an example to illustrate what is meant by
> "partial ordering" here?

In addition to Matt Fowles explanation I would like to
give the following example lattice build from the roles

role A { has $.x }
role B { has $.y }
role C { has $.z }

There can be the four union combined roles A|B, A|C, B|C
and A|B|C which complete the type lattice:

Any={}
/ | \
/ | \
/ | \
/ | \
/ | \
A={x} B={y} C={z}
| \ / \ / |
| \ / \ / |
| \/ \/ |
| /\ /\ |
| / \ / \ |
| / \ / \ |
A|B={x,y} A|C={x,z} B|C={y,z}
\ | /
\ | /
\ | /
\ | /
\ | /
A|B|C={x,y,z}

Note that A = (A|B) & (A|C) is the intersection type of A|B and A|C.
Note further that A|B is a subtype of A and B written A|B <: A and
A|B <: B and so on. Usually the A|B|C is called Bottom or some such.
I think it is the Whatever type of Perl6. It is the glb (greatest lower
bound) of A, B and C. In a larger lattice this type gets larger as well.
Any is the trivial supertype of all types.

This lattice can then be used for type checks and specificity
comparisons in dispatch. BTW, such a lattice can be calculated lazily
from any set of packages. In pure MMD the selected target has to be
the most specific in all dispatch relevant positions.

Regards,
--

TSa

unread,
Oct 9, 2006, 8:39:24 AM10/9/06
to perl6-l...@perl.org
HaloO,

TSa wrote:
> Note that the superclass interface of roles should be mostly inferred
> from the usage of next METHOD. As such it is a useful guidance for
> error reports in the class composition process.

Actually 'next METHOD' doesn't catch all superclass interface issues.
There is the simple case of calling e.g. accessor methods on super
which should result in the requirement to provide them. So I still
propose a super keyword that in roles means the object as seen from
the uncomposed class.


Regards,
--

TSa

unread,
Oct 9, 2006, 10:13:39 AM10/9/06
to perl6-l...@perl.org
HaloO,

Stevan Little wrote:
> I do not think method combination should be the default for role
> composition, it would defeat the composeability of roles because you
> would never have conflicts.

I don't get that. The type system would give compile time errors.
The current spec means that in case of a "conflicting" method the
class version simply overrides the role version. That is there is
simple, short or long name based "conflict" checking with priority
to the class.


> > I see that quite different: roles are the primary carrier of type
> > information!
>
> Well yes, they do seem to have taken on this role ;).

If it is not roles that carry type information then the Perl6 type
system is as of now completely unspecced. Even with roles I miss
some clear statements about their theoretical background.


> However, roles
> as originally envisioned in the Traits paper are not related to the
> type system, but instead related to class/object system. In fact the
> Trait paper gave it's examples in Smalltalk, which is not a strongly
> typed language (unless you count the idea that *everything* is an
> object and therefore that is their type).

Remember the paper did not include state for traits and thus nicely
avoided several typing issues particularly in SmallTalk that is based
on single inheritance and dispatch along these lines.


> I think we need to be careful in how we associate roles with the type
> system and how we assocaite them with the object system. I worry that
> they will end up with conflicting needs and responsibilities and roles
> will end up being too complex to be truely useful.

My current understanding is that properly typed roles can obliviate
the need of the things described in theory.pod and directly go with
F-bounded polymorphism as the theoretical model of the type system.
It e.g. is strong enough to model Haskell type classes. Note that there
are free mixins that pose no requirements on the class in the theory


as described in the article.

> > Dispatch depends on a partial ordering of roles.
>
> Type based dispatch does (MMD), but class based method dispatch
> doesn't need it at all.

I strongly agree. The two hierarchies should be separated. The
only interweaving that occurs is the class composition process.
And this process should IMHO be directed by the type system and
provide for method combination when the correct typing of the role
requires it. Typical examples that need method combination are
equality checking, sorting support and generic container types.

There seems to be another connection from the class hierarchy to
the role hierarchy that is that a class has a role of the same
name so that class names can be used where a type is expected or
however this is supposed to work. In the end there shall be some
mixing of class and type based dispatch or some kind of embedding
of the class dispatch into type dispatch.


> The whole fact that dispatching requires roles to be partially ordered
> actually tells me that maybe roles should not be so hinged to the type
> system since roles are meant to be unordered.

But how else do we define a subtype relation if not through a role
type lattice?


> Possiblely we should be seeing roles as a way of *implementing* the
> types, and not as a core component of the type system itself?

Hmm, again what is the type system then? All indications from the
Synopsis and this list go for roles taking over the responsibility
of key player in the type department. E.g. type parameters also go
with roles not with classes.


Regards,
--

TSa

unread,
Oct 9, 2006, 11:02:22 AM10/9/06
to TSa, perl6-l...@perl.org
HaloO,

TSa wrote:
> Note that A = (A|B) & (A|C) is the intersection type of A|B and A|C.
> Note further that A|B is a subtype of A and B written A|B <: A and
> A|B <: B and so on. Usually the A|B|C is called Bottom or some such.
> I think it is the Whatever type of Perl6. It is the glb (greatest lower
> bound) of A, B and C. In a larger lattice this type gets larger as well.
> Any is the trivial supertype of all types.

Damn it! I always puzzle glb and lub (least upper bound). So it should
read lub there. This is because the intension set gets larger even
though a subtype is formed. Note that the extension set "the instances"
becomes smaller! In a limiting case the Whatever type has got no
instances at all :)

Sorry,
--

Brad Bowman

unread,
Oct 10, 2006, 9:38:57 PM10/10/06
to perl6-l...@perl.org

I think the word "super" is already to overloaded to be used for this
purpose. Setting that aside for now...

Do you mean that super.blah() appearing in a method defined in a role A
should require that all classes which do A need to provide a blah
implementation? (or produce a composition time error if they don't)

I'd prefer to have a declarative mechanism for specifying such requirements.
Firstly for self-documenting clarity, there's no need to scan for a "super",
and secondly because eval and super.$method_name would allow runtime failures.
Some alternatives appeared elsewhere in this thread but it's unclear whether
they would produce error at composition time or at runtime. (yada methods)

The same applies to the "next METHOD" inference suggested:


> Note that the superclass interface of roles should be mostly inferred
> from the usage of next METHOD.

A Role should be able to say "to do this Role you need to implement these
methods" and have a compile/composition time error if not.

(There does need to be a way to call, in a Role A, both the "blah" defined
in A and whatever the "blah" the final class may use. $self.blah() is the
later, $self.A::blah() or similar is likely to be the former.)

Brad

--
When one is not capable of true intelligence, it is good to consult with
someone of good sense. -- Hagakure http://bereft.net/hagakure/

Jonathan Lang

unread,
Oct 10, 2006, 11:14:40 PM10/10/06
to Brad Bowman, perl6-l...@perl.org
Brad Bowman wrote:
> TSa wrote:
> > TSa wrote:
> >> Note that the superclass interface of roles should be mostly inferred
> >> from the usage of next METHOD. As such it is a useful guidance for
> >> error reports in the class composition process.
> >
> > Actually 'next METHOD' doesn't catch all superclass interface issues.
> > There is the simple case of calling e.g. accessor methods on super
> > which should result in the requirement to provide them. So I still
> > propose a super keyword that in roles means the object as seen from
> > the uncomposed class.

What do you mean by "uncomposed class"?

> I think the word "super" is already to overloaded to be used for this
> purpose. Setting that aside for now...
>
> Do you mean that super.blah() appearing in a method defined in a role A
> should require that all classes which do A need to provide a blah
> implementation? (or produce a composition time error if they don't)

I hope not; that's exactly what declaring an unimplemented method in a
role is supposed to do. (And declaring an implemented method does the
same thing, with the addition that it also suggests an implementation
that the class is free to use or ignore as it sees fit.)

> The same applies to the "next METHOD" inference suggested:
> > Note that the superclass interface of roles should be mostly inferred
> > from the usage of next METHOD.
>
> A Role should be able to say "to do this Role you need to implement these
> methods" and have a compile/composition time error if not.

Agreed.

> (There does need to be a way to call, in a Role A, both the "blah" defined
> in A and whatever the "blah" the final class may use. $self.blah() is the
> later, $self.A::blah() or similar is likely to be the former.)

No, there doesn't. Given that C<class Foo does A> and C<role A does
B>, There needs to be a way to call, in class Foo, both the "blah"
defined in Foo, the "blah" defined in A (so that Foo can reimplement
A's version as a different method or as part of its own), and the
"blah" defined in B; and there needs to be a way to call, in role A,
both the "blah" defined in Foo and the "blah" defined B; but role A
does not need a way to explicitly call a method defined in A. It
should assume that if Foo overrides A's implementation of blah, Foo
knows what it's doing; by the principle of least surprise, Foo should
never end up overriding A's implementation of blah only to find that
the original implementation is still being used by another of the
methods acquired from A.

--
Jonathan "Dataweaver" Lang

Jonathan Lang

unread,
Oct 10, 2006, 11:39:49 PM10/10/06
to TSa, perl6-l...@perl.org

So if I'm reading this right, a class that does both A and B should be
"lower" in the partial ordering than a class that does just one or the
other. And if A does B, then you'll never have a class that does just
A without also doing B, which trims out a few possible nodes and paths
from the lattice for practical purposes:

Any={}
| \
| \
| \
| \
| \


B={y} C={z}
/ \ |
/ \ |
/ \ |
/ \ |
/ \ |

/ \ |
A|B={x,y} B|C={y,z}


\ /
\ /
\ /
\ /
\ /
A|B|C={x,y,z}

I note that while the lattice is related to whatever role hierarchies
may or may not exist, it is not the same as them. In particular,
roles that have no hierarchal relationship to each other _will_ exist
in the same lattice. In fact, all roles will exist in the same
lattice, on the first row under "Any". Right? Or does the fact that
"A does B" mean that A would be placed where "A|B" is, and "A|C" would
end up in the same node as "A|B|C"?

> This lattice can then be used for type checks and specificity
> comparisons in dispatch. BTW, such a lattice can be calculated lazily
> from any set of packages. In pure MMD the selected target has to be
> the most specific in all dispatch relevant positions.

By "most specific", you'd mean "closest to the top"?

--
Jonathan "Dataweaver" Lang

TSa

unread,
Oct 11, 2006, 5:05:57 AM10/11/06
to perl6-l...@perl.org
HaloO,

Jonathan Lang wrote:
> What do you mean by "uncomposed class"?

The self always refers to the object as instance of the composed
class. Methods are therefore resolving to the outcome of the
composition process. But super in a role refers to methods from
the class definition even when the final method comes from method
combination in the composition process.


>> I think the word "super" is already to overloaded to be used for
>> this purpose. Setting that aside for now...

Better ideas? Is there a super keyword already? Or do you mean
overloaded in general OO and type speak?


>> Do you mean that super.blah() appearing in a method defined in a
>> role A should require that all classes which do A need to provide a
>> blah implementation? (or produce a composition time error if they
>> don't)

Yes, this is exactly what I mean with superclass interface of roles.


> I hope not; that's exactly what declaring an unimplemented method in
> a role is supposed to do.

My idea is that the type system calculates a type bound for the class
from the definition of the role. That includes attributes and their
accessor methods. It's a matter of taste how explicit this interface
is declared or how much of it is infered.


> (And declaring an implemented method does
> the same thing, with the addition that it also suggests an
> implementation that the class is free to use or ignore as it sees
> fit.)

We have a priority conflict here. The question is if the class or the
role is seeing the other's methods for method combination.


>> A Role should be able to say "to do this Role you need to implement
>> these methods" and have a compile/composition time error if not.
>
> Agreed.

I agree as well. But on a wider scope then just method provision.


>> (There does need to be a way to call, in a Role A, both the "blah"
>> defined in A and whatever the "blah" the final class may use.

Yes, this is the subject of the current debate. I'm opting for a
method combination semantics that allows the role to call the class
method.


>> $self.blah() is the later, $self.A::blah() or similar is likely to
>> be the former.)
>
> No, there doesn't. Given that C<class Foo does A> and C<role A does
> B>, There needs to be a way to call, in class Foo, both the "blah"
> defined in Foo, the "blah" defined in A (so that Foo can reimplement
> A's version as a different method or as part of its own), and the
> "blah" defined in B;

From the class all composed parts are available through namespace
qualified names. But a role is a classless and instanceless entity.
The self refers to the objects created from the composed class. The role
is not relevant in method dispatch. That is a method is never dispatched
to a role. But the role should be able to participate in the method
definition of the composed class.


> and there needs to be a way to call, in role A,
> both the "blah" defined in Foo and the "blah" defined B; but role A
> does not need a way to explicitly call a method defined in A.

I'm not sure if I get this right. But as I said above a role can not
be dispatched to. Which method do you think should take precedence
the role's or the class's? That is who is the defining entity in the
method combination process? I would hope it is the role if a as of now
unknown syntax has declared it. Perhaps it should be even the default.
The rational for my claim is that a role is composed several times
and then every class doing the role automatically gets the correct
version. Otherwise all classes are burdened with caring for the role's
part in the method.


> It
> should assume that if Foo overrides A's implementation of blah, Foo
> knows what it's doing; by the principle of least surprise, Foo should
> never end up overriding A's implementation of blah only to find that
> the original implementation is still being used by another of the
> methods acquired from A.

Could you make an example because I don't understand what you mean with
original implementation and how that would be used by role methods.
Method dispatch is on the class never on the role. As far as dispatch is
concerned the role is flattend out. But the question is how the class's
method is composed in the first place.


Regards,
--

TSa

unread,
Oct 11, 2006, 6:43:22 AM10/11/06
to perl6-l...@perl.org
HaloO,

Jonathan Lang wrote:
> So if I'm reading this right, a class that does both A and B should be
> "lower" in the partial ordering than a class that does just one or the
> other. And if A does B, then you'll never have a class that does just
> A without also doing B, which trims out a few possible nodes and paths
> from the lattice for practical purposes:
>
> Any={}
> | \
> | \
> | \
> | \
> | \
> B={y} C={z}
> / \ |
> / \ |
> / \ |
> / \ |
> / \ |
> / \ |
> A|B={x,y} B|C={y,z}
> \ /
> \ /
> \ /
> \ /
> \ /
> A|B|C={x,y,z}

Correct. The lattice is a structural analysis of the roles.


> I note that while the lattice is related to whatever role hierarchies
> may or may not exist, it is not the same as them. In particular,
> roles that have no hierarchal relationship to each other _will_ exist
> in the same lattice. In fact, all roles will exist in the same
> lattice, on the first row under "Any". Right?

Yes, if they are disjoined structurally. Otherwise intersection roles
appear as nodes under Any.


> Or does the fact that
> "A does B" mean that A would be placed where "A|B" is, and "A|C" would
> end up in the same node as "A|B|C"?

To get at the node labeled A|B above you either need a definition

role A does B { has $.x }

or an outright full definition

role A { has $.x; has $.y }

So, yes the node should be called A and A|C coincides with A|B|C.

I'm not sure if this ordering of roles can be called duck typing
because it would put roles that have the same content into the
same lattice node. The well known bark method of Dog and Tree
comes to mind. But the arrow types of the methods will be different.
One has type :(Dog --> Dog) the other :(Tree --> Tree) and a joined
node will have type :(Dog&Tree --> Dog|Tree). This might just give
enough information to resolve the issues surrounding the DogTree
class.


> By "most specific", you'd mean "closest to the top"?

No, closer to the bottom. The join operator | of the lattice produces
subtypes with a larger interface that is more specific. It's like
the more derived class in a class hierarchy.


Regards, TSa.
--

Jonathan Lang

unread,
Oct 11, 2006, 1:31:04 PM10/11/06
to TSa, perl6-l...@perl.org
TSa wrote:
> Jonathan Lang wrote:
> > What do you mean by "uncomposed class"?
>
> The self always refers to the object as instance of the composed
> class. Methods are therefore resolving to the outcome of the
> composition process. But super in a role refers to methods from
> the class definition even when the final method comes from method
> combination in the composition process.

Still not following. Can you give an example?

> > I hope not; that's exactly what declaring an unimplemented method in
> > a role is supposed to do.
>
> My idea is that the type system calculates a type bound for the class
> from the definition of the role. That includes attributes and their
> accessor methods. It's a matter of taste how explicit this interface

> is declared or how much of it is inferred.

Note that it's entirely possible for attributes to not make it into
the final class, if the accessor methods get redefined in such a way
as to remove reference to the attributes. This is part of the notion
that roles supply an outline of what the class should do, but only the
class actually supplies the definitive details of how to do it.

As I see it: "is" and "does" declarations in a role impose
requirements on the final class: it must derive from another class
("is"), or it must compose another role ("does"). "method" and "has"
are each one part requirement and one part suggestion: for "method",
the class is required to include a method that matches the given name
(which, of course, includes the method's signature), and a particular
closure is suggested that the class can accept or override.

For "has", the class is required to provide accessor methods
corresponding to the attribute's read/write capabilities (a rw method
if it's a rw attribute; a regular method if it's a regular attribute;
and no method if it's a private attribute); like any other method, a
closure is suggested that the class may accept or override. In
addition, the role suggests that a given attribute be added to the
class' state information. This suggestion is implicitly accepted if
any of the methods that are used by the final class refer to the
attribute; it is implicitly rejected if none of them do. The same
rule applies to private methods.

Thus, the only things that I'd recommend using to calculate a
type-boundary would be the superclasses (provided by "is") and the
method names (provided by "method" and "has").

> > (And declaring an implemented method does
> > the same thing, with the addition that it also suggests an
> > implementation that the class is free to use or ignore as it sees
> > fit.)
>
> We have a priority conflict here. The question is if the class or the
> role is seeing the other's methods for method combination.

I believe that I address this later on; if not, please clarify.

> >> (There does need to be a way to call, in a Role A, both the "blah"
> >> defined in A and whatever the "blah" the final class may use.
>
> Yes, this is the subject of the current debate. I'm opting for a
> method combination semantics that allows the role to call the class
> method.

Agreed.

> >> $self.blah() is the later, $self.A::blah() or similar is likely to
> >> be the former.)
> >
> > No, there doesn't. Given that C<class Foo does A> and C<role A does
> > B>, There needs to be a way to call, in class Foo, both the "blah"
> > defined in Foo, the "blah" defined in A (so that Foo can reimplement
> > A's version as a different method or as part of its own), and the
> > "blah" defined in B;
>
> From the class all composed parts are available through namespace
> qualified names. But a role is a classless and instanceless entity.
> The self refers to the objects created from the composed class. The role
> is not relevant in method dispatch. That is a method is never dispatched
> to a role. But the role should be able to participate in the method
> definition of the composed class.

Also agreed. In particular, I'm referring to _how_ a role should
participate in the method definition of the composed class; I am not
referring to method dispatch, which is limited to the class hierarchy.

> > and there needs to be a way to call, in role A,
> > both the "blah" defined in Foo and the "blah" defined B; but role A
> > does not need a way to explicitly call a method defined in A.
>
> I'm not sure if I get this right. But as I said above a role can not
> be dispatched to. Which method do you think should take precedence
> the role's or the class's? That is who is the defining entity in the
> method combination process?

I agree with the idea behind the current definition of this: if the
class provides its own definition for a method, that should take
precedence over the role's definition. If it doesn't, then it adopts
the role's definition as its own.

> I would hope it is the role if a as of now
> unknown syntax has declared it. Perhaps it should be even the default.
> The rational for my claim is that a role is composed several times
> and then every class doing the role automatically gets the correct
> version. Otherwise all classes are burdened with caring for the role's
> part in the method.

Huh?

> > It
> > should assume that if Foo overrides A's implementation of blah, Foo
> > knows what it's doing; by the principle of least surprise, Foo should
> > never end up overriding A's implementation of blah only to find that
> > the original implementation is still being used by another of the
> > methods acquired from A.
>
> Could you make an example because I don't understand what you mean with
> original implementation and how that would be used by role methods.

role A {
method foo() { say "Ah..." }
method bar() { $self.foo() }
}

class Foo does A { }

class Bar does A {
method foo() { say "Oh..." }
}

class Baz does A {
method foo() {
$self.A::foo();
say "Choo!";
}
method baz() { $self.A::foo() }
}

The above should be exactly equivalent to:

class Foo {
method foo() { say "Ah..." }
method bar() { $self.foo() }
}

class Bar {
method foo() { say "Oh..." }
method bar() { $self.foo() }
}

class Baz {
method foo() {
$self!'A::foo'();
say "Choo!";
}
method bar() { $self.foo() }
method baz() { $self!'A::foo'() }
my method 'A::foo'() { say "Ah..." }
}

(The optimizer should remove the extraneous curly braces.)

So:

Foo.foo(); # "Ah...\n"
Foo.bar(); # "Ah...\n"
Bar.foo(); # "Oh...\n"
Bar.bar(); # "Oh...\n"
Baz.foo(); # "Ah...\nChoo!\n"
Baz.bar(); # "Ah...\nChoo!\n"
Baz.baz(); # "Ah...\n"

In Baz, C<my method 'A::foo'()> represents the original implementation
of foo(), while C<method foo()> represents the final implementation
chosen by the class.

If you were to allow a role method to directly refer to its own
implementation, you could do something like:

role A {
method foo() { say "Ah..." }
method bar() { $self.A::foo() }
}

Substituting this version of role A into my original example would
lead to this sort of output:

Foo.foo(); # "Ah...\n"
Foo.bar(); # "Ah...\n"
Bar.foo(); # "Oh...\n"
Bar.bar(); # "Ah...\n"
Baz.foo(); # "Ah...\nChoo!\n"
Baz.bar(); # "Ah...\n"
Baz.baz(); # "Ah...\n"

On reflection, this wouldn't neccessarily be as bad as I originally
thought. I don't see why anyone would want to use it; but it's
identified for what it is clearly enough that someone reading the role
will know what to expect when he starts making changes to things.

> Method dispatch is on the class never on the role. As far as dispatch is
> concerned the role is flattend out. But the question is how the class's
> method is composed in the first place.

Agreed. Hopefully, the above sheds some light on where I'm coming from.

--

Re: Partial Ordering


> I'm not sure if this ordering of roles can be called duck typing
> because it would put roles that have the same content into the
> same lattice node. The well known bark method of Dog and Tree
> comes to mind.

IIRC, duck typing is based on how well the set of available method
names match, its main flaw coming from the possibility of homonymous
methods. With the Dog and Tree example, consider the possibility that
both versions of "bark" take no parameters other than the invocant,
and neither version returns anything. Their signatures would thus be
identical (since the invocant's type is the final class' type).

> But the arrow types of the methods will be different.
> One has type :(Dog --> Dog) the other :(Tree --> Tree) and a joined
> node will have type :(Dog&Tree --> Dog|Tree). This might just give
> enough information to resolve the issues surrounding the DogTree
> class.

Not sure what you mean by "the arrow types". Are you referring to
embedding a return type in the signature?

> > By "most specific", you'd mean "closest to the top"?
>
> No, closer to the bottom. The join operator | of the lattice produces
> subtypes with a larger interface that is more specific. It's like
> the more derived class in a class hierarchy.

Got it.

--
Jonathan "Dataweaver" Lang

TSa

unread,
Oct 12, 2006, 6:53:51 AM10/12/06
to perl6-l...@perl.org
HaloO,

Jonathan Lang wrote:
> Still not following. Can you give an example?

The example in the original post contains a class GenSquare that
has got an equal method that checks the sides of the self square
and the incoming argument square. The GenPointMixin role provides
an equal method that compares the x and y coordinates. The correct
final method equal of the composed class needs to check sides and
coordinates. If the simple side checking equal of the class
overrides the closure from the role there is a false implementation.
OTOH, forcing all classes to call the role closure is bad design of
the composition process. Hence I'm arguing for a super keyword that
in a role refers to the class. In the example super.equal($p) calls
the side checking closure.


> Note that it's entirely possible for attributes to not make it into
> the final class, if the accessor methods get redefined in such a way
> as to remove reference to the attributes. This is part of the notion
> that roles supply an outline of what the class should do, but only the
> class actually supplies the definitive details of how to do it.

I see that you regard the class as the ultimate definer of
functionality. The role requires a method including its signature
but the class implements it. For the type system the role encodes
the guarantee of the method availability.


> As I see it: "is" and "does" declarations in a role impose
> requirements on the final class: it must derive from another class
> ("is"), or it must compose another role ("does"). "method" and "has"
> are each one part requirement and one part suggestion: for "method",
> the class is required to include a method that matches the given name
> (which, of course, includes the method's signature), and a particular
> closure is suggested that the class can accept or override.

I almost agree here. The only thing I'm asking for is that the role's
closure is not discarded so easily. The designer of the role takes
responsibility for the role's part in the final method closure. The
combination process should produce the correct result automatically
and independent of the class's cooperation.


> Thus, the only things that I'd recommend using to calculate a
> type-boundary would be the superclasses (provided by "is") and the
> method names (provided by "method" and "has").

That makes classes too typeish. The type system is mostly based on
roles. The class inheritance graph should not be used for typing.
Or do you want constraints on the class derivation process that
guarantees subclasses to be subtypes? As I read it the class derivation
is free to violate replaceability of subclasses where superclasses
are expected. Roles are a guarantee of functionality not classes.


> I agree with the idea behind the current definition of this: if the
> class provides its own definition for a method, that should take
> precedence over the role's definition. If it doesn't, then it adopts
> the role's definition as its own.
>
>> I would hope it is the role if a as of now
>> unknown syntax has declared it. Perhaps it should be even the default.
>> The rational for my claim is that a role is composed several times
>> and then every class doing the role automatically gets the correct
>> version. Otherwise all classes are burdened with caring for the role's
>> part in the method.
>
> Huh?

Yeah! The role adds a certain aspect to the correct implementation of
a method. And so does the class. But it is the role that is composed
into the class not the other way around. A role is intended to be
composed several times into completely different classes. With blind
precedence to class methods the role's aspects are lost and have to
be reintroduced in each and every class. I consider that inconvenient
and error prone.


>> > It
>> > should assume that if Foo overrides A's implementation of blah, Foo
>> > knows what it's doing; by the principle of least surprise, Foo should
>> > never end up overriding A's implementation of blah only to find that
>> > the original implementation is still being used by another of the
>> > methods acquired from A.
>>
>> Could you make an example because I don't understand what you mean with
>> original implementation and how that would be used by role methods.
>
> role A {
> method foo() { say "Ah..." }
> method bar() { $self.foo() }
> }

Isn't that self.foo() without the sigil? It is clear that .foo
is dispatched on the class.

> [..]


> class Baz {
> method foo() {
> $self!'A::foo'();
> say "Choo!";
> }
> method bar() { $self.foo() }
> method baz() { $self!'A::foo'() }
> my method 'A::foo'() { say "Ah..." }
> }

What is A referring to here? Baz doesn't compose role A here.
And why the exclamation mark?


> In Baz, C<my method 'A::foo'()> represents the original implementation
> of foo(), while C<method foo()> represents the final implementation
> chosen by the class.

OK, thanks for the example.


> If you were to allow a role method to directly refer to its own
> implementation, you could do something like:
>
> role A {
> method foo() { say "Ah..." }
> method bar() { $self.A::foo() }
> }

Yes, this should call the role closure from within the class.


With precedence to class methods my original example should read

role GenPointMixin
{
has Int $.x;
has Int $.y;
method class_equal ( : ::?CLASS $p ) {...}
method equal( : ::?CLASS $p --> Bool )
{
return self.class_equal(p) and


self.x == $p.x and self.y == $p.y;
}
}

which is clumsy and relies on the fact that the class is *not*
overriding the equal method but of course provides the class_equal
method. I want that combination process to be available under the
equal name slot. Which requires the role to take precedence at least
for the equal method. The question is what syntax to use for this
feature. I propose a 'is augmented' trait on the role method.


> Re: Partial Ordering
>> I'm not sure if this ordering of roles can be called duck typing
>> because it would put roles that have the same content into the
>> same lattice node. The well known bark method of Dog and Tree
>> comes to mind.
>
> IIRC, duck typing is based on how well the set of available method
> names match, its main flaw coming from the possibility of homonymous
> methods. With the Dog and Tree example, consider the possibility that
> both versions of "bark" take no parameters other than the invocant,
> and neither version returns anything. Their signatures would thus be
> identical (since the invocant's type is the final class' type).

Conceptually the methods take and return the invocant type. This
is why I gave them as :(Dog --> Dog) and :(Tree --> Tree) respectively.
That's what I meant with arrow types. But Void as return type is fine
as well. The question is now how these two signatures are merged
together to form the signature required from the class disambiguation.
The glb Dog&Tree to me means that a common supertype be implemented
in the class. Hmm, this at least is what contravariant arrow types
demand. But I'm as of now puzzled if it's not better to require the
class to implement the lub Dog|Tree based on the idea that this makes
instances of the class subtypes of both interfaces. The implementation
of which obliges to the class. Well, invocant parameters are covariant.
So, yes it should be a method on Dog|Tree the type of instances of a
class that does Dog and Tree.


>> But the arrow types of the methods will be different.
>> One has type :(Dog --> Dog) the other :(Tree --> Tree) and a joined
>> node will have type :(Dog&Tree --> Dog|Tree). This might just give
>> enough information to resolve the issues surrounding the DogTree
>> class.
>
> Not sure what you mean by "the arrow types". Are you referring to
> embedding a return type in the signature?

I mean arrow types as used in formal treatments of type systems.
Functions are denoted with arrows there. This is also the reason why
we have the --> in signatures.


Regards, TSa.
--

Jonathan Lang

unread,
Oct 12, 2006, 12:10:53 PM10/12/06
to TSa, perl6-l...@perl.org
TSa wrote:
> HaloO,
>
> Jonathan Lang wrote:
> > Still not following. Can you give an example?
>
> The example in the original post contains a class GenSquare that
> has got an equal method that checks the sides of the self square
> and the incoming argument square. The GenPointMixin role provides
> an equal method that compares the x and y coordinates. The correct
> final method equal of the composed class needs to check sides and
> coordinates. If the simple side checking equal of the class
> overrides the closure from the role there is a false implementation.

Actually, the correct equal method for the composed class needs to
check the sides of the square, because how the class defines it: in
this example, class GenSquare _is_ the final class, and so whatever
method it provides _is_ the final method, for good or ill. If this
results in other method definitions inherited from GenPointMixin
behaving strangely, then GenSquare needs to override those methods as
well.

Mind you, the above implies a radical shift in the underlying
semantics, akin to having class Dog compose role Tree and redefining
method bark() to suit its own nature. Proper use of role composition
is to refine the role's underlying concept, not to radically alter it.
Even if we were to go with a modified version of the original
example, where GenSquare is a role and both GenSquare and GenPoint are
being composed into a final class - say, "GenPositionedSquare" - you
still have the problem that the final class is conceptually supposed
to be both a GenSquare and a GenPoint at the same time. If the
underlying concepts behind the composed roles are fundamentally
incompatable (such as a Dog and a Tree), you're going to have
problems.

> OTOH, forcing all classes to call the role closure is bad design of
> the composition process. Hence I'm arguing for a super keyword that
> in a role refers to the class. In the example super.equal($p) calls
> the side checking closure.

This is what happens by default; no special syntax is needed.

> > Note that it's entirely possible for attributes to not make it into
> > the final class, if the accessor methods get redefined in such a way
> > as to remove reference to the attributes. This is part of the notion
> > that roles supply an outline of what the class should do, but only the
> > class actually supplies the definitive details of how to do it.
>
> I see that you regard the class as the ultimate definer of
> functionality. The role requires a method including its signature
> but the class implements it. For the type system the role encodes
> the guarantee of the method availability.

Exactly.

> > As I see it: "is" and "does" declarations in a role impose
> > requirements on the final class: it must derive from another class
> > ("is"), or it must compose another role ("does"). "method" and "has"
> > are each one part requirement and one part suggestion: for "method",
> > the class is required to include a method that matches the given name
> > (which, of course, includes the method's signature), and a particular
> > closure is suggested that the class can accept or override.
>
> I almost agree here. The only thing I'm asking for is that the role's
> closure is not discarded so easily. The designer of the role takes
> responsibility for the role's part in the final method closure. The
> combination process should produce the correct result automatically
> and independent of the class's cooperation.

Perl has yet to implement a telepathic compiler, so the compiler can
only make best guesses as to what the programmer intended. For now,
we have to make some concessions to reality; one such concession is
that the most specific thing should have authority over (and
responsibility for) the less specific things. The thing being
composed into is by definition more specific than the thing being
composed when it comes to implementation; thus, the latter should be
given free rein to redefine the methods provided by the former - and
if things go wrong, you should blame the latter rather than the
former. Letting a role override a decision made by a class that it's
composed into means that there's something about the role's
implementation that the class cannot touch.

> > Thus, the only things that I'd recommend using to calculate a
> > type-boundary would be the superclasses (provided by "is") and the
> > method names (provided by "method" and "has").
>
> That makes classes too typeish. The type system is mostly based on
> roles. The class inheritance graph should not be used for typing.

It is a fact that class inheritance affects the behaviour of a class;
it cannot be disregarded when considering type.

That said, class inheritance (with respect to its semantic differences
from role composition) is an area where my understanding is rather
shaky. To me, the whole notion of inheritance is a bit too typeish
for my tastes; I try to handle _all_ code reuse by means of roles,
with classes only being brought into play when I want to be able to
instantiate an object. That is, I tend to define what an object is
exclusively by what it does.

BTW, whoever writes the Perl 6 reference book has a golden opportunity
to highlight a bit of conceptual elegance. In perl 6, there are three
ways to handle code reuse: "is" (class inheritance), "does" (role
composition), and "has" (attribute delegation).

> Or do you want constraints on the class derivation process that
> guarantees subclasses to be subtypes?

I'm not sure what you mean here. In particular, Perl uses "subtype"
in a very specific way - and which is antithetical to "subclass".
roles and subclasses expand an object's capabilties; subtypes restrict
them.

> As I read it the class derivation
> is free to violate replaceability of subclasses where superclasses
> are expected. Roles are a guarantee of functionality not classes.

What do you mean by "replaceability of subclasses"?

> >> I would hope it is the role if a as of now
> >> unknown syntax has declared it. Perhaps it should be even the default.
> >> The rational for my claim is that a role is composed several times
> >> and then every class doing the role automatically gets the correct
> >> version. Otherwise all classes are burdened with caring for the role's
> >> part in the method.
> >
> > Huh?
>
> Yeah! The role adds a certain aspect to the correct implementation of
> a method. And so does the class. But it is the role that is composed
> into the class not the other way around. A role is intended to be
> composed several times into completely different classes.

I'm with you so far...

> With blind
> precedence to class methods the role's aspects are lost and have to
> be reintroduced in each and every class. I consider that inconvenient
> and error prone.

That's where you're losing me. I don't see how "blind" precedence to
class methods would cause the results that you describe.

>
> >> > It
> >> > should assume that if Foo overrides A's implementation of blah, Foo
> >> > knows what it's doing; by the principle of least surprise, Foo should
> >> > never end up overriding A's implementation of blah only to find that
> >> > the original implementation is still being used by another of the
> >> > methods acquired from A.
> >>
> >> Could you make an example because I don't understand what you mean with
> >> original implementation and how that would be used by role methods.
> >
> > role A {
> > method foo() { say "Ah..." }
> > method bar() { $self.foo() }
> > }
>
> Isn't that self.foo() without the sigil? It is clear that .foo
> is dispatched on the class.

No; it's $self with the sigil. $self is the scalar that contains the
invocant.

> > [..]
> > class Baz {
> > method foo() {
> > $self!'A::foo'();
> > say "Choo!";
> > }
> > method bar() { $self.foo() }
> > method baz() { $self!'A::foo'() }
> > my method 'A::foo'() { say "Ah..." }
> > }
>
> What is A referring to here? Baz doesn't compose role A here.
> And why the exclamation mark?

Note the single quotes around C<A::foo>. 'A' isn't referring to
anything; it's literally part of the name.

The exclamation mark indicates that I'm accessing a private method.
Likewise, the 'my' means that I'm _defining_ a private method.

> > If you were to allow a role method to directly refer to its own
> > implementation, you could do something like:
> >
> > role A {
> > method foo() { say "Ah..." }
> > method bar() { $self.A::foo() }
> > }
>
> Yes, this should call the role closure from within the class.

I still don't see a purpose for it.

> With precedence to class methods my original example should read
>
> role GenPointMixin
> {
> has Int $.x;
> has Int $.y;
> method class_equal ( : ::?CLASS $p ) {...}
> method equal( : ::?CLASS $p --> Bool )
> {
> return self.class_equal(p) and
> self.x == $p.x and self.y == $p.y;
> }
> }
>
> which is clumsy and relies on the fact that the class is *not*
> overriding the equal method but of course provides the class_equal
> method.

OK; I just tried to decipher your original example. If I'm
understanding it correctly, what you're actually wanting to say is
this:

role GenEqual
{
method equal( GenEqual $p --> Bool ) {...}
}


role GenPoint


{
has Int $.x;
has Int $.y;

method equal( GenPoint $self: GenPoint $p --> Bool )
{
return $self.x == $p.x and $self.y == $p.y;
}
}

class GenSquare does GenPoint does GenEqual
{
has Int $.side;
method equal ( GenSquare $p --> Bool )
{
return $self.GenPoint::equal($p) and $self.side == $p.side;
}
}

Note that GenPoint no longer makes any reference to GenSquare.

> > Re: Partial Ordering
> >> I'm not sure if this ordering of roles can be called duck typing
> >> because it would put roles that have the same content into the
> >> same lattice node. The well known bark method of Dog and Tree
> >> comes to mind.
> >
> > IIRC, duck typing is based on how well the set of available method
> > names match, its main flaw coming from the possibility of homonymous
> > methods. With the Dog and Tree example, consider the possibility that
> > both versions of "bark" take no parameters other than the invocant,
> > and neither version returns anything. Their signatures would thus be
> > identical (since the invocant's type is the final class' type).
>
> Conceptually the methods take and return the invocant type.

They don't have to; and the duck-typing problem occurs most
prominantly when they don't.

> The question is now how these two signatures are merged
> together to form the signature required from the class disambiguation.

Signatures shouldn't be merged.

--
Jonathan "Dataweaver" Lang

TSa

unread,
Oct 13, 2006, 3:22:50 AM10/13/06
to perl6-l...@perl.org
HaloO,

Jonathan Lang wrote:
> class GenSquare does GenPoint does GenEqual
> {
> has Int $.side;
> method equal ( GenSquare $p --> Bool )
> {
> return $self.GenPoint::equal($p) and $self.side == $p.side;
> }
> }

This is exactly what I don't want. Such an equal method needs to be
written in each and every class the role GenPoint is composed into.
This is what I call a burden instead of code reuse by means of role
composition. But I guess our points of view are hard to reconcile.
You and the current spec see the class having the final word whereas
I think that the role takes over responsibility. This does not require
a telepathic compiler. Simply giving priority to the role suffices.

Having the role in charge nicely matches the fact that the guarantee
of doing a role makes a stronger claim than being an instance of a
class. Doing the role happens with objects from different classes.
And now imagine that some classes implemented equality correctly and
some don't. With my approach the chance for this is diminished to
a correct class specific implementation that is required and used by
the role.


Regards, TSa.
--

Jonathan Lang

unread,
Oct 17, 2006, 9:50:57 AM10/17/06
to perl6language,
TSa wrote:
> Jonathan Lang wrote:
> > TSa wrote:
> >> This is exactly what I don't want. Such an equal method needs to be
> >> written in each and every class the role GenPoint is composed into.
> >
> > No, it doesn't. It only needs to be written in those classes where
> > the 'equal' method is supposed to behave differently than the one
> > found in GenPoint.
>
> Grumpf, yes. But I think that equality checking is something that needs
> to deal with some class specific data. And hence the care-taking for
> the role needs to be implemented many times while it could come out of
> the composition process almost for free. I assume the class specific
> part needs writing anyway.

OK; I think I see where you're coming from.

I don't think that the behaviour that you're describing should be Perl
6's default behavior; but I _could_ see implementing a sort of
"reverse delegation" trait that causes a role's class to start the
dispatch process for a given method with the role instead of the
class. Something like:

role GenPointMixin
{
is divert(:equal<GenPointMixin>);


has Int $.x;
has Int $.y;

method equal( ::?CLASS GenEqual $self: ::?CLASS $p --> Bool )
{
return $self.::?CLASS::equal($p) and $self.x == $p.x and
$self.y == $p.y;
}
}

Of course, you then run into a problem if the class _doesn't_ redefine
method equal; if it doesn't, then what is GenPointMixin::equal
calling? And you also run into a problem if you want the class to
track the position in polar coordinates instead of rectilinear ones -
it would still represent a point conceptually, but the implementation
of method equal (at least) would need to be overridden.

Or you could change the dispatch rules throughout the lexical scope
where the classes are defined with a 'use' statement; all's fair if
you predeclare, after all. But you'd still have the above issues.

A cleaner solution would be to define a private helper method which
the role then demands that the class override. This is _very_ similar
to the solution that you described as "clumsy" a few posts back, with
the main difference being that the helper method, being private, can't
be called outside of the class. To me, the only clumsiness of this
solution comes directly from the cluminess of the overall example, and
I consider your proposed alternative to be equally clumsy - it merely
trades one set of problems for another.

> And yes, in Perl 6 the method isn't called equal but eqv or === and
> has a default implementation that retrieves the .WHICH of both args.

What inspired that comment?

--
Jonathan "Dataweaver" Lang

TSa

unread,
Oct 17, 2006, 10:14:47 AM10/17/06
to perl6language,
HaloO Jonathan,

you wrote:
> Of course, you then run into a problem if the class _doesn't_ redefine
> method equal; if it doesn't, then what is GenPointMixin::equal
> calling?

This is the reason why there is a type bound on the class that should
result in a composition error when the equal method is missing.

Shouldn't the 'divert' be a trait of the method instead of a key/value
pair on the class? And what does your syntax mean? Looks like the key
is indicating the method and the value is the namespace where method
lookup starts.


> And you also run into a problem if you want the class to
> track the position in polar coordinates instead of rectilinear ones -
> it would still represent a point conceptually, but the implementation
> of method equal (at least) would need to be overridden.

Oh, yes. Doing the right thing is difficult. Changing representation
of the point while keeping the interface can only be done in the class.
OTOH, the interface would include the rectilinear accessor methods.
And these are called in the equal method. Thus a class doing the
GenPoint role correctly needs to provide .x and .y methods even if
they aren't simple auto-generated accessors of attributes. But note
that these two are not going through the superclass interface but the
self type.

In the case of the equal method the dispatch slot contains the role's
closure which calls into the class' closure. There is no dispatch to the
role because the role is flattened out in the composition process.

It is interesting to think of another PolarPoint role that also has
an equal method that would conflict with the GenPoint one. Then the
class has to disambiguate. Which in turn requires the class to provide
an equal method that overrides both role versions. Note that I think
the conflict detection of role methods prevents the composition of the
equal method through the superclass interface. I admit that this warps
the meaning of the class' equal method from beeing an aspect in the
role's method to the definer of the method. This can be a source of
subtle bugs. That is the class composer can't distinguish an aspect
method from a disambiguation one unless we introduce e.g. an 'is
disambig' trait. And e.g. an 'is override' trait when the class designer
wishes to replace a role method even if there's no conflict.


> A cleaner solution would be to define a private helper method which
> the role then demands that the class override. This is _very_ similar
> to the solution that you described as "clumsy" a few posts back, with
> the main difference being that the helper method, being private, can't
> be called outside of the class. To me, the only clumsiness of this
> solution comes directly from the cluminess of the overall example, and
> I consider your proposed alternative to be equally clumsy - it merely
> trades one set of problems for another.

There's a lot of truth in that. But I don't consider the example as
clumsy. It is an important issue that arises whenever method
recombination is needed to deal with the guarantees that the role
as a type makes. Calculation of a type bound on the class that
has to be met in the composition is a strong tool.


>> And yes, in Perl 6 the method isn't called equal but eqv or === and
>> has a default implementation that retrieves the .WHICH of both args.
>
> What inspired that comment?

Sorry, I didn't want to intimidate you. But I wanted to prevent comments
that choosing a method equal is not the right approach and MMD should be
used instead. But I think all of what we discussed so far stays valid if
the equal method is a multi. IIRC there is just one namespace slot for
the short name. And we are discussing how this slot is filled in the
class composition process.

BTW, why have you gone off-list?


Regards, TSa.
--

Jonathan Lang

unread,
Oct 17, 2006, 10:36:32 AM10/17/06
to TSa, perl6language,
TSa wrote:
> Jonathan Lang wrote:
> > Of course, you then run into a problem if the class _doesn't_ redefine
> > method equal; if it doesn't, then what is GenPointMixin::equal
> > calling?
>
> This is the reason why there is a type bound on the class that should
> result in a composition error when the equal method is missing.

But it isn't missing; it's being inherited from the role.

> Shouldn't the 'divert' be a trait of the method instead of a key/value
> pair on the class?

I thought about doing it that way; but then the class wouldn't know to
look for it when composing the role.

> And what does your syntax mean? Looks like the key
> is indicating the method and the value is the namespace where method
> lookup starts.

That was the idea.

> > And you also run into a problem if you want the class to
> > track the position in polar coordinates instead of rectilinear ones -
> > it would still represent a point conceptually, but the implementation
> > of method equal (at least) would need to be overridden.
>
> Oh, yes. Doing the right thing is difficult. Changing representation
> of the point while keeping the interface can only be done in the class.
> OTOH, the interface would include the rectilinear accessor methods.
> And these are called in the equal method.

...unless the equal method is rewritten so that it doesn't call them.
That said, you're right that the rectlinear access methods will still
be there - but they won't neccessarily work the same way. In
particular, I can see .x being rewritten to return $.r * cos($.a) when
used to retrieve the value. Internally, the representation would be
in polar notation; externally, rectilinear accessors could still be
used - though they wouldn't be as efficient as polar accessors.

> In the case of the equal method the dispatch slot contains the role's
> closure which calls into the class' closure. There is no dispatch to the
> role because the role is flattened out in the composition process.

Conceptually, yes; you can think of it in that way. In practice, this
is implemented by having the class dispatch to the role if none of the
class' signatures match the call. Bear in mind, though, that _every_
call follows this route: even a method call that originates in a
role's method (such as an attribute accessor) will start the dispatch
process with the class, then move to the roles if the class doesn't
work, and then move up the class hierarchy if the roles don't work.

> It is interesting to think of another PolarPoint role that also has
> an equal method that would conflict with the GenPoint one. Then the
> class has to disambiguate. Which in turn requires the class to provide
> an equal method that overrides both role versions.

Agreed.

> Note that I think the conflict detection of role methods prevents the
> composition of the equal method through the superclass interface.

Just to make sure we're speaking the same language: by "superclass",
you're referring to classes brought in via "is"; right? If so, you're
correct: the presence of a valid method in any of the roles that a
class composes is sufficient to prevent the dispatch process from ever
reaching any of the superclasses.

> I admit that this warps

> the meaning of the class' equal method from being an aspect in the


> role's method to the definer of the method. This can be a source of
> subtle bugs. That is the class composer can't distinguish an aspect
> method from a disambiguation one unless we introduce e.g. an 'is
> disambig' trait. And e.g. an 'is override' trait when the class designer
> wishes to replace a role method even if there's no conflict.

...and you would then have to apply the 'override' trait to every
class method that is used instead of the role method. Note that as
written, this is the default approach, and you only have to do
something exotic in the (comparatively) rare situation where you want
the class to complete the role's method instead of replacing it.

> > What inspired that comment?
>
> Sorry, I didn't want to intimidate you.

I wasn't intimidated; just curious.

--
Jonathan "Dataweaver" Lang

TSa

unread,
Oct 17, 2006, 12:18:36 PM10/17/06
to perl6language,
HaloO,

Jonathan Lang wrote:
> TSa wrote:

>> Note that I think the conflict detection of role methods prevents the
>> composition of the equal method through the superclass interface.
>
> Just to make sure we're speaking the same language: by "superclass",
> you're referring to classes brought in via "is"; right?

No. I used the term 'superclass interface' as it appears in the
article I referred to. There the role has a type constraint interface
to the uncomposed class which is available through the super keyword.
Let's settle for the terms 'uncomposed class' and 'composed class'.
Then I meant the interface of the role to the uncomposed class.

It might be the case that you should think of the role composition
to happen on a new anonymous class that inherits everything from the
uncomposed class and therefore has a proper superclass interface.
Conflicts between roles prevent the installation of a composed method
and hence leave the task of defining it to the composed class.
I admit that the distinction between these cases can come as a surprise
to class developers. But composing more than one role is equal in
complexity as multiple inheritance. So a warning is a good thing here.
The 'is override' trait might be needed to silence the warning. Well,
and you can switch it off with a pragma or the trait on the class.

The whole point of the article is to calculate the composed class type.
This process is akin to inheritance but needs two implicit type
parameters to model it in F-bounded polymorphism. Free mixins just go
into the composed class unconstraint. Constraint mixins require certain
features from the class. This inevitably shifts the balance between
roles and classes towards roles which is OK in my eyes. In particular
since roles have taken on the meaning of type in Perl 6 and as such
make the stronger claims when used where a type is expected.


> If so, you're
> correct: the presence of a valid method in any of the roles that a
> class composes is sufficient to prevent the dispatch process from ever
> reaching any of the superclasses.

I'm more thinking along the lines of closure composition and a flattened
view of the class. That is conceptually the class' namespace directly
maps slot names to methods. That this mapping is searching the
inheritance graph behind the scenes is an implementation detail. In the
case of roles the composed method calls the uncomposed one that's all.
In your terms this means 'dispatch starts at the role' I guess.

On a side track I want to note: the optimizer might munge all combined
methods into an optimized version that doesn't walk the class graph. In
the GenSquare case this method reads

return self.side == $p.side and self.x == $p.x and self.y == $p.y

and is installed in the equal slot of the composed class. I'm
interpreting roles from a type theoretical background. This is viable
because all information needed is available at compile time whereas
classes are open.

Note that the combination process as I see it nicely explains runtime
role composition in the same way as compile time role composition. There
is no special rule that at runtime the role takes precedence or forces
its definition of methods. Also the difference between successive does
and a precomposed role with | falls out naturally. In the latter case
conflicts let role methods drop out and leave the class method as
"disambiguation". But the compiler can easily issue a warning for that.


Regards, TSa.
--

TSa

unread,
Oct 17, 2006, 12:24:16 PM10/17/06
to perl6language,
HaloO,

Jonathan Lang wrote:
>> Shouldn't the 'divert' be a trait of the method instead of a key/value
>> pair on the class?
>
> I thought about doing it that way; but then the class wouldn't know to
> look for it when composing the role.

I figure you see the class in a very active role when composing roles.
I see them more as a passive entity that the class composer is dealing
with. My scope is on producing a predictable result from the typing
point of view. Dispatch comes later.

Regards, TSa.
--

Jonathan Lang

unread,
Oct 17, 2006, 7:22:59 PM10/17/06
to perl6language
I think I found the core of the issue here; it has to do with the
differences between roles and mixins, with an analogous difference
between compile-time composition and runtime composition. Details
follow.

TSa wrote:
> Jonathan Lang wrote:

> > Just to make sure we're speaking the same language: by "superclass",
> > you're referring to classes brought in via "is"; right?
>
> No. I used the term 'superclass interface' as it appears in the
> article I referred to. There the role has a type constraint interface
> to the uncomposed class which is available through the super keyword.

Ah. Unfortunately, said article is part 15 of a series. While it's
true that only a handful of them are directly referenced by the
article, that's still more than I've had time to read so far - and the
unreferenced articles still matter in that they provide the
grammatical context in which Article 15 is phrased.

> Let's settle for the terms 'uncomposed class' and 'composed class'.
> Then I meant the interface of the role to the uncomposed class.

Let me figure out what you mean by 'uncomposed class' and 'composed
class' before I agree to the terminology. The original article seems
to be making an assumption that you will always take an existing class
and a mixin in order to create a new class. If this is the
assumption, then the existing class would be the 'uncomposed class',
the mixin would be the 'role', and the new class would be the
'composed class'.

This, however, is not the default paradigm used by Perl 6. If you
want to do this sort of thing in perl 6, you say something like:

class ComposedClass is UncomposedClass does Role { ... }

In particular, perl 6 does not assume the existence of an uncomposed
class when using roles unless you explicitly specify one: there is
just the role and the composed class that fleshes out that role.
This, I believe, is the fundamental difference between roles and
mixins: the latter assumes that it's being mixed in to something
pre-existing to produce something new; the former doesn't.

Just to clarify some terminology: in the above statement,
'ComposedClass' composes 'Role', and 'ComposedClass' inherits from
'UncomposedClass'. Conversely, 'Role' is composed into
'ComposedClass'.

'UncomposedClass' is a superclass of 'ComposedClass', 'ComposedClass'
is a subclass of 'UncomposedClass', and 'Role' is a role of
'ComposedClass'. AFAIK, there's no standard term for what
'ComposedClass' is in relation to 'Role' - though personally, I'd tend
to say that 'ComposedClass' is an implementation of 'Role'.

My understanding is that mixin terminology would be that 'role' is
mixed into 'UncomposedClass' to produce 'ComposedClass'.

> It might be the case that you should think of the role composition
> to happen on a new anonymous class that inherits everything from the
> uncomposed class and therefore has a proper superclass interface.

The only situation in perl6 that I know of where an anonymous class is
generated when a role is composed is when you compose the role at
runtime.

Incidently, your comments to date are much more compatable with
runtime composition than they are with compile-time composition. In
fact, a case could be made that runtime composition always uses the
mixin paradigm, whereas compile-time composition doesn't.

The paradigm used by compile-time composition is that the role acts as
a blueprint for building the class. It does not get "mixed in" to
anything; it instead provides requirements that the class must meet,
and an optional toolkit that the class may use in meeting those
requirements.

> Conflicts between roles prevent the installation of a composed method
> and hence leave the task of defining it to the composed class.

This is how things work now, during compile-time: if two roles provide
potentially incompatable method implementations, the class is required
to supply a replacement for them.

If I understand runtime composition correctly, undefined methods in a
role fall back on the uncomposed class' definitions; this means that
it is an error to compose a role at runtime that declares a method
that the uncomposed class lacks without defining it, even if a later
role in the sequence provides a definition for it.

> I admit that the distinction between these cases can come as a surprise
> to class developers. But composing more than one role is equal in
> complexity as multiple inheritance. So a warning is a good thing here.
> The 'is override' trait might be needed to silence the warning. Well,
> and you can switch it off with a pragma or the trait on the class.

The distinction _does_ come as a surprise to me, but only because perl
handles single-role composition in a way that's fully compatable with
the multiple-role composition strategy that you just outlined. That
is, perl doesn't make a distinction; it assumes single-role
composition to be a special case of multiple-role composition.

> The whole point of the article is to calculate the composed class type.
> This process is akin to inheritance but needs two implicit type
> parameters to model it in F-bounded polymorphism.

"F-bounded polymorphism"?

> Free mixins just go into the composed class unconstraint.

Do you mean "unconstrained"? Incidently, this is a distinction that I
don't think that perl makes: If I'm reading this right, all roles in
perl are essentially constraint mixins (for some definition of
"mixin").

> Constraint mixins require certain features from the class.

As do roles in perl, yes. The difference is in what is required.
Roles specifically limit themselves to requiring certain methods to be
defined in the class (for some definition of "class"); and they
specifically do not require anything about how those methods are to be
defined.

> Note that the combination process as I see it nicely explains runtime
> role composition in the same way as compile time role composition.

Since you're essentially redefining the latter to more closely
resemble the former, this is no surprise.

> There
> is no special rule that at runtime the role takes precedence or forces
> its definition of methods. Also the difference between successive does
> and a precomposed role with | falls out naturally. In the latter case
> conflicts let role methods drop out and leave the class method as
> "disambiguation". But the compiler can easily issue a warning for that.

I've never really been happy with the inconsistency between runtime
composition and compile-time composition; but my problem has generally
been with the runtime side of things - in particular, I find the fact
that "does A does B does C" has an ordering at runtime to be annoying.
I understand the need for ordered composition; without it, there
would be no reliable way to resolve disputes between roles without
falling back to the original class (which isn't an option when the
goal is to change that aspect of the class' behavior).

Personally, I would rather see "does A does B does C" be unordered in
all cases, and use something like "does A & does B & does C" to
represent ordered composition (where '&' hints at its "delayed
evaluation" behavior in other situations). Or maybe use "also", in
analogy to how a class can be defined in stages during compile-time;
but '&' is probably better Huffman coding for this.

--
Jonathan "Dataweaver" Lang

TSa

unread,
Oct 18, 2006, 9:14:29 AM10/18/06
to p6l
HaloO Jonathan,

you wrote:
> I think I found the core of the issue here; it has to do with the
> differences between roles and mixins, with an analogous difference
> between compile-time composition and runtime composition. Details
> follow.

I think we are basically through the discussion. Thank you for your
patience so far. It's interesting to note that you make a distinction
between mixins and roles. I think of roles as being mixins.


> Ah. Unfortunately, said article is part 15 of a series. While it's
> true that only a handful of them are directly referenced by the
> article, that's still more than I've had time to read so far - and the
> unreferenced articles still matter in that they provide the
> grammatical context in which Article 15 is phrased.

The series is worth reading, indeed.


> Just to clarify some terminology: in the above statement,
> 'ComposedClass' composes 'Role', and 'ComposedClass' inherits from
> 'UncomposedClass'. Conversely, 'Role' is composed into
> 'ComposedClass'.

This is still not how I think of it. I'm more thinking of the
composition process as having the *same* class in a pre- and a
post-composition state. The role poses a type constraint on the
pre-state and can access this state. There's no inheritance
between two classes.

As you describe it, the current compile-time composition let's
the role define a type bound of the composition result in the
sense that instances of the class do the role.


> "F-bounded polymorphism"?

See e.g.
http://www.cs.utexas.edu/~wcook/papers/FBound89/CookFBound89.pdf
http://www.cs.washington.edu/research/projects/cecil/www/Vortex-Three-Zero/doc-cecil-lang/cecil-spec-86.html

The basic idea is to define the type T of instances of a class
or role as all types that are subtypes of a type function:

forall T <: Generator[T]

The crux is that T appears on both sides of the typing relation.
I would like to find out how it can be applied to Perl 6.
So if you find the time to read through the series we can try
together to understand the type system of Perl 6.


>> Free mixins just go into the composed class unconstraint.
>
> Do you mean "unconstrained"?

Yes, sorry for the typo.


Regards, TSa.
--

Jonathan Lang

unread,
Oct 18, 2006, 10:56:30 AM10/18/06
to p6l
TSa wrote:
> you wrote:
> > I think I found the core of the issue here; it has to do with the
> > differences between roles and mixins, with an analogous difference
> > between compile-time composition and runtime composition. Details
> > follow.
>
> I think we are basically through the discussion. Thank you for your
> patience so far. It's interesting to note that you make a distinction
> between mixins and roles. I think of roles as being mixins.

I'm only making the distinction based on a very restrictive definition
of "mixin" - and I'm doing so largely to illustrate the conceptual
differences between compile-time and runtime composition.

> > Just to clarify some terminology: in the above statement,
> > 'ComposedClass' composes 'Role', and 'ComposedClass' inherits from
> > 'UncomposedClass'. Conversely, 'Role' is composed into
> > 'ComposedClass'.
>
> This is still not how I think of it. I'm more thinking of the
> composition process as having the *same* class in a pre- and a
> post-composition state.

I see it now. I still don't agree with using it as the default
approach; but I see it.

> As you describe it, the current compile-time composition lets


> the role define a type bound of the composition result in the
> sense that instances of the class do the role.

Note that because perl 6 uses a prototype approach to
object-orientation, the class itself counts as an instance of the
class.

--
Jonathan "Dataweaver" Lang

Larry Wall

unread,
Oct 18, 2006, 12:17:27 PM10/18/06
to perl6language
On Tue, Oct 17, 2006 at 04:22:59PM -0700, Jonathan Lang wrote:
: I've never really been happy with the inconsistency between runtime

: composition and compile-time composition; but my problem has generally
: been with the runtime side of things - in particular, I find the fact
: that "does A does B does C" has an ordering at runtime to be annoying.
: I understand the need for ordered composition; without it, there
: would be no reliable way to resolve disputes between roles without
: falling back to the original class (which isn't an option when the
: goal is to change that aspect of the class' behavior).
:
: Personally, I would rather see "does A does B does C" be unordered in
: all cases, and use something like "does A & does B & does C" to
: represent ordered composition (where '&' hints at its "delayed
: evaluation" behavior in other situations). Or maybe use "also", in
: analogy to how a class can be defined in stages during compile-time;
: but '&' is probably better Huffman coding for this.

You've got it inside out. Unordered is just "does A | B | C" or
some such, the | there really being coerced to a set construction,
not a junction. In fact, & would work just as well. I only used |
because it's more readable. Autocoercion of junctions to sets is,
of course, conjectural. You really have

does set(A,B,C)

The | notation is mentioned in S012:1029, by the way. Obviously you
still haven't quite memorized all the synopses. :-)

Larry

Jonathan Lang

unread,
Oct 18, 2006, 4:32:14 PM10/18/06
to perl6language
Larry Wall wrote:
> You've got it inside out. Unordered is just "does A | B | C" or
> some such, the | there really being coerced to a set construction,
> not a junction. In fact, & would work just as well. I only used |
> because it's more readable. Autocoercion of junctions to sets is,
> of course, conjectural. You really have
>
> does set(A,B,C)

I wasn't aware that you were using set semantics there; but other than
that clarification, I knew exactly what Unordered is - see below.

> The | notation is mentioned in S012:1029, by the way. Obviously you
> still haven't quite memorized all the synopses. :-)

Actually, I was very well aware of that fact. The above was a
proposal for changing S12, for the express purpose of making the
syntax for unordered composition at run-time look like the syntax for
unordered composition at compile-time as much as possible (by the
principle of least surprise). Since this would remove the current
syntax for doing ordered composition at runtime, and given that
ordered composition at runtime is not something we want to lose, I was
also proposing a replacement syntax for it. So instead of

role R does A does B does C { ... } # unordered composition
$x does A does B does C; # ordered composition
$y does A | B | C; # unordered composition

I'd like to see it done something like:

role R does A does B does C { ... } # unordered composition
$x does A & does B & does C; # ordered composition
$y does A does B does C; # unordered composition

Same capabilities, but less cognitive dissonance.

Mind you, I don't really care what syntax gets used for ordered
composition; just as long as it isn't "does A does B does C".

--
Jonathan "Dataweaver" Lang

Larry Wall

unread,
Oct 18, 2006, 9:11:37 PM10/18/06
to perl6language
Though actually, now that I think about it, the cascaded notation
in S12 is illegal according to S03, since "does" is classified as
non-chaining, which implies non-associative. Hmm. We'd have to make
it right associative somehow. Put it in with ** maybe?

Hmm.

Or leave it non-associative and force | or ; notation to keep things
crystal clear. The basic problem is that the declarational "does" has
a natural scope that it applies to, so it doesn't have to arbitrarily
limit its scope as a binary operator does.

Larry

Larry Wall

unread,
Oct 18, 2006, 8:49:36 PM10/18/06
to perl6language
On Wed, Oct 18, 2006 at 01:32:14PM -0700, Jonathan Lang wrote:
: >The | notation is mentioned in S012:1029, by the way. Obviously you

: >still haven't quite memorized all the synopses. :-)
:
: Actually, I was very well aware of that fact.

Oops, didn't realize you were suggesting a semantic change to the default,
not just a syntactic addition.

: The above was a


: proposal for changing S12, for the express purpose of making the
: syntax for unordered composition at run-time look like the syntax for
: unordered composition at compile-time as much as possible (by the
: principle of least surprise). Since this would remove the current
: syntax for doing ordered composition at runtime, and given that
: ordered composition at runtime is not something we want to lose, I was
: also proposing a replacement syntax for it. So instead of
:
: role R does A does B does C { ... } # unordered composition
: $x does A does B does C; # ordered composition
: $y does A | B | C; # unordered composition
:
: I'd like to see it done something like:
:
: role R does A does B does C { ... } # unordered composition
: $x does A & does B & does C; # ordered composition
: $y does A does B does C; # unordered composition
:
: Same capabilities, but less cognitive dissonance.

Gotcha. Sorry my brain was in sidewayser than usual.

: Mind you, I don't really care what syntax gets used for ordered


: composition; just as long as it isn't "does A does B does C".

I suspect ordered composition is going to be rare enough that we can
simply dehuffmanize it to

$x does A;
$x does B;
$x does C;

Larry

Jonathan Lang

unread,
Oct 19, 2006, 1:34:20 AM10/19/06
to perl6language

Personally, I'd rather it be right-associative: if

class Foo is Bar does A does B { ... }

works, I'd expect

$x does A does B;

to work, too.

What trouble would we get into by moving "does" to the chaining
binaries priority (i.e., one step more restrictive than it currently
is)?

--
Jonathan "Dataweaver" Lang

Ruud H.G. van Tol

unread,
Oct 19, 2006, 3:35:50 AM10/19/06
to perl6-l...@perl.org
Larry Wall schreef:

> I suspect ordered composition is going to be rare enough that we can
> simply dehuffmanize it to
>
> $x does A;
> $x does B;
> $x does C;

Maybe use a list-like notation?

$x does (A, B, C,) ;
$x does (A ; B ; C) ;

$x does [A, B, C,] ;
$x does [A ; B ; C] ;

--
Groet, Ruud

TSa

unread,
Oct 19, 2006, 4:51:21 AM10/19/06
to perl6language
HaloO,

Larry Wall wrote:
> You've got it inside out. Unordered is just "does A | B | C" or
> some such, the | there really being coerced to a set construction,
> not a junction. In fact, & would work just as well. I only used |
> because it's more readable. Autocoercion of junctions to sets is,
> of course, conjectural. You really have
>
> does set(A,B,C)

I would like "does A & B & C" mean the intersection type of A, B and C.
That is a supertype of all three roles. In addition we might need
negation to get what Jonathan Lang envisoned for the Complex type that
does Num & !Comparable. IOW, I'm opting for a role combination syntax
by means of logical operators that operate on the intension set of the
involved roles. Could we get that?

BTW, the synopsis reserve Foo[Bar] and Foo{Bar} for type theoretical
operations. The former is used for parametric types. How is the latter
used?


Regards, TSa.
--

TSa

unread,
Oct 19, 2006, 5:57:23 AM10/19/06
to perl6language
HaloO

TSa wrote:
> I would like "does A & B & C" mean the intersection type of A, B and C.
> That is a supertype of all three roles. In addition we might need
> negation to get what Jonathan Lang envisoned for the Complex type that
> does Num & !Comparable. IOW, I'm opting for a role combination syntax
> by means of logical operators that operate on the intension set of the
> involved roles. Could we get that?

And while we're at it, could we also introduce the subtype operator <:
and perhaps >: as the supertype operator? This would come in handy for
expressing type constraints in does clauses.
--

Jonathan Lang

unread,
Oct 19, 2006, 8:50:16 AM10/19/06
to perl6-l...@perl.org
Ruud H.G. van Tol wrote:
> Larry Wall schreef:
>
> > I suspect ordered composition is going to be rare enough that we can
> > simply dehuffmanize it to
> >
> > $x does A;
> > $x does B;
> > $x does C;
>
> Maybe use a list-like notation?

What happens when you try to mix ordered and unordered composition?
Under the current syntax, to compose roles A and B together, and then
C once A and B are done, one could say:

$x does A | B does C;

Under my original suggestion, this would be:

$x does A does B & does C;

Under Larry's suggestion, this would be:

$x does A does B;
$x does C;

How would you handle it?

If ordered composition is something that can be done in a single
statement, then unordered composition syntax needs to be nestable
inside ordered composition syntax - and since the goal here is to have
"does A does B" always represent unordered composition, that's what
would need to nest.

--

Despite having suggested a possible syntax for ordered composition, I
think that Larry is right in claiming that a sequence of separate
composition statements is more than sufficient in both syntax and
clarity to handle those cases where ordered composition is needed.

--
Jonathan "Dataweaver" Lang

Jonathan Lang

unread,
Oct 19, 2006, 9:06:26 AM10/19/06
to perl6language
TSa wrote:
> And while we're at it, could we also introduce the subtype operator <:
> and perhaps >: as the supertype operator? This would come in handy for
> expressing type constraints in does clauses.

Isn't one of those called ".does()"?

--
Jonathan "Dataweaver" Lang

TSa

unread,
Oct 19, 2006, 9:33:31 AM10/19/06
to perl6-l...@perl.org
HaloO,

Hmm, no one seems to read the article! There actually is another class
GenLocSquare that combines GenSquare and GenPointMixin. With that we
get a modified version of my code as follows:

> role GenEqual
> {
> method equal( : GenEqual $ --> Bool ) {...}
> }
>
> role GenPointMixin
> {


> has Int $.x;
> has Int $.y;
> method equal( ::?CLASS GenEqual $self: ::?CLASS $p --> Bool )

This additional GenEqual type bound on the self type is all
that is needed to get the superclass interface as described
in the article.

> {
> return super.equal(p) and # <-- handwave

return call($p) and # normal superclass call, but I still
# think that super.equal reads better.

> self.x == $p.x and self.y == $p.y;
> }
> }
>
> class GenSquare does GenEqual does GenPointMixin

class GenSquare does GenEqual

> {
> has Int $.side;
> method equal ( : ::?CLASS $p --> Bool )
> {
> return self.side == $p.side;
> }
> }

And finally the combined class

class GenLocSquare is GenSquare does GenPointMixin
{}

I initially dropped it because I thought that roles can see
the pre-composed class somehow. But as Jonathan explained they
don't---at least not in compile-time class composition. And
for runtime composition you get the empty class for free!


Regards, TSa.
--

Dr.Ruud

unread,
Oct 19, 2006, 10:00:01 AM10/19/06
to perl6-l...@perl.org
"Jonathan Lang" schreef:

> role R does A does B does C { ... } # unordered composition
> $x does A does B does C; # ordered composition
> $y does A | B | C; # unordered composition
>
> I'd like to see it done something like:
>
> role R does A does B does C { ... } # unordered composition
> $x does A & does B & does C; # ordered composition
> $y does A does B does C; # unordered composition

And I was on the line of:

role R does A | B | C { ... } # unordered composition
$x does ( A, B, C ) ; # ordered composition


$y does A | B | C ; # unordered composition

but I would like early and late binding to be explicit.
Maybe the coder will use () around the run-time ones.

--
Affijn, Ruud

"Gewoon is een tijger."

Jonathan Lang

unread,
Oct 19, 2006, 6:31:18 PM10/19/06
to perl6language
Larry Wall wrote:
> Though actually, now that I think about it, the cascaded notation
> in S12 is illegal according to S03, since "does" is classified as
> non-chaining, which implies non-associative.

Wait a minute. Isn't "chaining" specifically referring to the idea
that "A op B op C" implicitly becomes something like "A op B && B op
C"? That would seem to be unrelated to the concept of associativity,
other than the fact that you can't have chaining without
associativity. Why would "does" have to be chaining in order to be
associative?

--
Jonathan "Dataweaver" Lang

Larry Wall

unread,
Oct 20, 2006, 7:47:04 PM10/20/06
to perl6language

I was using "non-chaining" to indicate a particular precedence
level. (In actual fact, all precedence levels but chaining are
non-chaining, but only one precedence level actually has that name.)
The non-chaining precedence level is a bunch non-associative operators
like .. and cmp. Historically, all operators of a particular precedence
level have had the same associativity, so that when you analyze

$a op1 $b op2 $c

you only have to compare op1 with op2 if they're the same precedence, and
given the prededence you don't actually have to look at the individual
ops. What would it mean to have a left-associative op at the same precedence
level as a right-associative op:

$a lefty $b righty $c

Who would win? So generally we try not to mix associativity within a
precedence level.

For now the conservative thing is probably that we should just leave
"does" as non-associative and make you write

$obj.also_does(A,B,C)

or some such if you want to get fancy.

Larry

Larry Wall

unread,
Oct 20, 2006, 7:56:36 PM10/20/06
to perl6language
On Fri, Oct 20, 2006 at 04:47:04PM -0700, Larry Wall wrote:
: For now the conservative thing is probably that we should just leave

: "does" as non-associative and make you write
:
: $obj.also_does(A,B,C)
:
: or some such if you want to get fancy.

Presumably

$obj does (A,B,C)

could also be made to work even with non-associative does.

Larry

Jonathan Lang

unread,
Oct 20, 2006, 10:14:17 PM10/20/06
to perl6language
Larry Wall wrote:
> Presumably
>
> $obj does (A,B,C)
>
> could also be made to work even with non-associative does.

Right.

Note that you _do_ want to be able to do something to the effect of
ordered composition in a single statement, though:

role A {
...
method m { ... }
}

$x does A;

A.m will override $x.m - assuming that $x.m exists at all. As such,
you end up with an anonymous class with an undefined method - a
distinct no-no.

Maybe what you need to say is that "$x does ..." is a macro that
treats what follows as part of an anonymous class definition. So

$x does A does B { method m { doit } }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
would be equivalent to something like

$x.WHAT := class is $x.WHAT does A does B { method m { doit } }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You'd need to have the macro work some magic involving curly-braces
and terminating semicolons, so that

$x does A;
doit;
...

becomes

$x.WHAT := class is $x.WHAT does A { }
doit;
...

instead of

$x.WHAT := class is $x.WHAT does A {
doit;
...
}

And you'd have to decide what to do with

$x does role { ... }
{ ... }

Should this become

$x.WHAT := class is $x.WHAT does role { ... } { ... }

or

$x.WHAT := class is $x.WHAT does role { ... } { }
{ ... }

?

But otherwise, this approach allows runtime composition to use exactly
the same syntax and semantics as compile-time composition as soon as
you hit infix:<does>.

--
Jonathan "Dataweaver" Lang

TSa

unread,
Oct 27, 2006, 3:44:47 AM10/27/06
to perl6-l...@perl.org
HaloO,

I wrote:
> And finally the combined class
>
> class GenLocSquare is GenSquare does GenPointMixin
> {}

I'm still pondering how one achieves method combination of the
role's and the class' methods. Here are two ideas. The first
is to use an 'is extended' part in the role that re-opens the
class when the role is composed. Question is how such a class
extension addresses the unextended class. Does the call($p) do
what I hope it does?

role GenPointMixin
{
has Int $.x;
has Int $.y;

is extended
{
method equal( ::?CLASS GenEqual: ::?CLASS $p --> Bool )
{
return call($p) and self.x == $p.x and self.y == $p.y;
}
}
}

The second idea is to subclass an anonymous class when the
role is composed. I don't know if this is valid syntax but
the anonymous class would provide a proper superclass interface
such that the equal method can be combined from the role's
definition that goes into the anonymous class and the uncomposed
class' version of the equal method. Note that the presence of
such a method is guaranteed by the GenEqual type constraint on
the invocant type of the method.

role GenPointMixin is ::?CLASS


{
has Int $.x;
has Int $.y;

method equal( ::?CLASS GenEqual: ::?CLASS $p --> Bool )
{
return call($p) and self.x == $p.x and self.y == $p.y;
}
}

Regards, TSa.
--

TSa

unread,
Oct 27, 2006, 5:59:21 AM10/27/06
to perl6-l...@perl.org
HaloO,

I wrote:
> role GenPointMixin
> {
> has Int $.x;
> has Int $.y;
> is extended
> {

That should be spelled 'is also'. How does such an
'is also' block address the former class definition
block? Is it OUTER::? Or SUPER::? The latter would mean
that class extension is a kind of pseudo-inheritance.


Regards, TSa.
--

0 new messages