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

Reply via email to