On Sat, Dec 13, 2003 at 12:50:50PM -0500, Austin Hastings wrote: : > -----Original Message----- : > From: Larry Wall [mailto:[EMAIL PROTECTED] : > Sent: Friday, December 12, 2003 8:30 PM : : > On Fri, Dec 12, 2003 at 05:17:37PM -0500, Austin Hastings wrote: : > : I presume that the linear order (compile time) or chronological order of : > : applying roles decides the order in which overlaid methods are : > : C<wrap>ed/overlaid. : > : > The original Traits paper specifies that it's illegal to compose two : > methods of the same name into the class, and you have to rename one of : > them to get them both visible. This is why the authors specifically : > rejected mixins, because they hide errors like this. : : I'm not convinced these are errors. Having a role override methods makes : sense in a lot of ways.
A role method certainly overrides inherited methods, so it's only methods defined in the class itself we're talking about here. : Consider, for example, a caching or persistence implementation that : overrides the .STORE method of its victims. I think the class is still the final arbiter of what its objects are--there is no other entity that holds all the reins. If a class chooses to include a role, and that role violates the normal rules of roles, the class is still responsible for that (or else you need some babysitting code somewhere, hopefully in the metaclass). Maybe that's what a trait is--a renegade role. Instead of does Storable maybe it's is storable : It seems to me there's an argument both ways -- : : 1. Code written in the absence of a role won't anticipate the role and : therefore won't take (unknowable) steps to disambiguate method calls. Ergo : method overloads are bad. : : 2. Roles may be written to deliberately supercede the methods of their : victims. Method overloads are vital. I think the default has to be 1, with an explicit way to get 2, preferably with the agreement of the class in question, though that's not absolutely necessary if you believe in AOP. : This doesn't take into account role vs. role conflicts (which seem more : likely to be serendipitous). : : Perhaps an "exact signature" rule would work? Such that if the method was an : exact replacement, then no error occurs, otherwise it becomes either an : error or a multi? Er, which method? : Alternatively, perhaps a role must declare its method to be multi or not, : and if not then the role's method overloads the original class's. No, I think the default needs to be such that the class's method is expected to dispatch to the role's method. If no such method exists then it falls back on the normal role method dispatch. In either case, it would almost always be the case that you'd want multimethod dispatch to the set of role methods of the same name. I'm starting to think that any methods declared in roles are automatically considered "multi" when composed, whether so declared or not. : (Which takes us to retroactive multi-fication. Ugh.) More like proactive multi-fication, I think. : Or perhaps you just have to say "this method overloads". If it's part of the role contract, it's part of the contract. But maybe that makes it a trait. : > As for the relationship of "Trait" methods to other methods : > declarations, an explicit method declaration in the class proper : > overrides the composed methods, while composed methods override : > anything else in the inheritance hierarchy. : : At compile time, right? Whereas composition (but=) overrides declaration at : run-time? I don't think the rules for run-time roles should be different than the rules for compile-time roles (because Perl doesn't make a hard-and-fast distinction between compile time and run time). And the arbitration logic has to be somehow associated with the class, either explicitly by the class's declarations, or by some babysitting code telling the class how to behave given the new composition. I've been talking about singleton classes to implement run-time roles, but that's not quite right. I think a class caches its various compositions and either reuses an existing one or creates a new composition depending on which set of roles has been bound to the current object. It might seem like you could have a combinatorial explosion of the possible number of compositions if multiple properties are applied at run time, but when you think about, the number of those cached compositions has to be equal or less than the number of singleton classes you'd get if you created a new one for every object with one or more properties. In general there will be many fewer compositions than singletons. So whenever you bind a run-time role, the class looks to see if it already knows how to do the combination of roles this object wants, and if so, the role binding is very fast. Otherwise it creates the new composition, checks for conflicts, resolves them (or doesn't), and then binds the new composition as the object's current view of its class. In a sense, these are the true mixins. The things people normally call "mixins" are more like "slatherons". Larry