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