Sorry for the top-post. I thought it was appropriate here as I've nothing I want to say on a particular basis other than "thank you" for a such a detailed, thoughtful answer. I appreciate it :)
Cheers, Ovid -- Buy the book - http://www.oreilly.com/catalog/perlhks/ Tech blog - http://use.perl.org/~Ovid/journal/ Twitter - http://twitter.com/OvidPerl Official Perl 6 Wiki - http://www.perlfoundation.org/perl6 ----- Original Message ---- > From: Stevan Little <stevan.lit...@iinteractive.com> > To: Ovid <publiustemp-catal...@yahoo.com> > Cc: moose@perl.org > Sent: Thursday, 16 July, 2009 5:57:25 > Subject: Re: Bug with Moose::Role attributes > > Hey Ovid, > > On Jul 15, 2009, at 2:24 PM, Ovid wrote: > > On the Perl 6 language list, Raphael Descamps posted a link to a paper > explaining how to implement stateful traits > (http://scg.unibe.ch/archive/papers/Berg07eStatefulTraits.pdf). One of the > authors of that paper worked on the original traits paper and the research > appears solid. > > I was actually approached by the authors of this paper before it was > published > but after they had finished the implementation. They were wondering how we > handled attribute conflicts in Perl 6/Moose. In Moose we will die on an > attribute conflict, this is basically punting because the this problem is > very > hard. I explained to them though that Moose attributes were significantly > more > complex then Smalltalk attributes so our more extreme solution was not really > applicable to them. Moose attributes are truly first class citizens of the > MOP > layer while Smalltalk simply has a list of slots in the instance and accessor > methods that are (IIRC) totally unrelated to them on any formal level. > > See the problem is that we (Moose) don't just have reader/writer methods to > worry about, but we have reader/writer or accessor, predicate methods, > clearer > methods, associated builder and lazy_build methods and then the possibility > of > delegation methods with handles. The result is that we have a *LOT* of things > to > check, and we don't want to just test this once on creation of the attribute, > but we actually need to compare the attribute to *every other attribute* the > class (and it's superclasses) have. This is the only way to be sure that we > are > not creating a conflict with a method that is somehow tied to an attribute > and > therefore to state. > > > Basically, it argues that traits need to have private accessors. > > Yeah, this is something I remember discussing with chromatic, Luke Palmer and > Audrey at YAPC::NA in Toronto. We kept going around and around on this never > coming to a totally satisfying solution. It basically always felt (to me > anyway) > that it was hiding the problem instead of actually dealing with it. Although > I > have not read the paper yet, so perhaps when i see their reasoning I might > feel > different. > > Also note that (at least some) of the authors or this paper expressed to me > that > they were not happy with this outcome. That having privacy in Smalltalk felt > very un-Smalltalk-ish and so the solution kind of felt dirty. I feel the same > way about this in regards to Perl, the idea of requiring privacy seems very > un-Perlish. > > > I won't go into full detail (you'll have to read the paper), but I decided > > to > see exactly how Moose handles this. I *think* this is a bug in Moose 0.87, > but > I'm unsure. > > Nope, this is a bug in Moose 0.01 (or whatever version it was we introduced > roles in). > > > > > > I would suggest a couple of things. > > > > 1. A class's attributes should silently override a role's attributes (I > > hate > this, but it's in keeping with what Moose does with class/role methods). > > The problem with this is that many of the roles methods will likely expect > the > attribute (and it's associated methods) to be there, so silently overriding a > role attribute is pretty much totally out of the question. While kinda > annoying > we do the only sensible thing here, which is to die. > > > 2. A class's methods MUST fail when trying to override a role's > > attributes, > thus forcing deliberate exclusion. This is because methods and attributes > serve > such radically different purposes that a failure here is warranted. > > Yes, I will agree here, but as of right now role attributes are not first > class > citizens so this is not possible. There was a lot of talk at this years > YAPC::NA > hackathon about actually making them first class, so rest assured it is being > addressed. > > > 3. A class's attributes MUST fail when trying to override a role's methods > (see above). > > Same as #2, I agree with you, but until we have first class role attributes > and > can calculate the methods they will create at composition time, we won't be > able > to fix this. > > > I expect that people will have different views, but that's OK. Have fun > > with > that. > > Well not me, except for the first item, which I suspect if you read my point > there you will agree with me on. > > > I would also love to see private attributes available for Moose roles. > > Yuk! I would prefer to solve the problem without them if possible. Privacy in > perl is hackish at best since you cannot really properly hide a method from > the > dispatcher (just die-ing when called from an improper context is *NOT* > correct > privacy, true privacy means that the method is invisible to the dispatcher > and > not present in the MRO). > > > Right now, that attribute in the role unnecessarily clutters the interface > > of > the class and there's no need for that. > > Unless of course that is the purpose of the role, to include an attribute. > Sure > I can see occasions when you do want to hide data, but it is not always the > case > and I would argue is more an exception then it is a rule. > > > Plus, the class shouldn't have to provide an attribute which only that role > uses because that violates the role's encapsulation. > > I think that the roles encapsulation has already been violated when it was > completed taken apart and all it's component bits shoved (composed) in the > class. Again, there is a case for data-hiding in some cases, but certainly > not > all. > > So, now that is out of the way, let me explain the rough plan that Yuval > Kogman > and I have been tossing around now for almost 3 years. > > Class::MOP needs some kind of low level "trait"-like mechanism (in this > context > "trait" means the things in the original traits paper, which is just sets of > pure methods and the composition rules that apply to them). These would be > primarily an internally used feature too and not something exposed in the > Moose > sugar. Lets call these "mop-traits" for now to avoid any confusion. > > Now, lets start with just classes first. > > The idea is that an attribute meta-object can actually produce one of these > "mop-traits" for itself. The result is a trait which defines all the methods > that would be associated with this particular attribute. This would includee > the > reader/writer/accessor, predicate, clearer and delegated methods for handles, > as > well as required methods for the builder/lazy_build methods. > > So then when a class is being composed, it asks each attribute (local and > inherited) to supply a mop-trait. It then takes all these mop-traits and > composes them all together into a single composite trait, applying all the > conflict resolution rules you would expect. The result is that we would be > able > to tell at this point if any of our attributes conflict with one another. > > Next we would ask the class itself to create a mop-trait of itself to > represent > all the methods (local and inherited) and we compose it with the attribute > composite trait. We do this because we want to apply trait-style conflict > detection and not class conflict detection (where the local class would win > and > superclass would loose, etc). > > The end result is that we are assured that no attributes conflict with one > another and no attribute created methods conflict with hand-defined methods. > > Sounds nice doesn't it :) > > It is also very expensive. Liberal use of caching and possibly doing the > mop-trait composition with something more optimized like Set::Object would > perhaps help, but this is all compile time cost and we already have a problem > with that in Moose. And just wait, it gets worse, we haven't even gotten to > roles yet. > > So, now throwing roles into the mix. > > A role attribute is a deferred attribute, meaning that it really has very > little > value (besides introspection maybe) until it is added into the class into > which > it is being composed. It also is context sensitive, different composition > contexts can produce different results (parameterized roles, etc). > > We would need to break down all the roles into sets of mop-traits in the same > was a the classes (first each of the attributes, then the methods). This > isn't > as bad for roles since they are already flattened and have no indirection to > resolve. This would assure us that each single role itself would be > internally > consistent. > > We would then need to compose all these roles together (assuming your > composing > multiple roles into your class) so that we could be sure that this particular > combination of roles is valid and non-conflicting. > > Then we would need to take all the mop-traits of our roles and compose them > with > all the mop-traits of our class (it's attributes and methods, as discussed > above), and let me tell you, that there is a whole mess-a composin' going on. > > A conflict in this process would basically signal a composition problem, and > if > we add some more error context info to the required methods that are produced > by > these conflicts we should be able to give some pretty good error messages, > especially since we wont have to die at the first sign of error. > > Now, again, we certainly will be able to cache things, especially if we can > keep > mop-trait composition as a pure (side-effect free) computation. > > ... > > So at this point when you call ->new on your class, it should shoot rainbows > out > of your computers USB drive and a unicorn should then appear and give you ice > cream (or some kind of frozen tofu treat if your are lactose intolerant or a > vegan). > > --- > > Now, I will be honest, I highly doubt you will see this in Moose 1.0, to do > it > right would really require a major overhaul in how things work right now and > would almost surely require us to be able to "compile" Moose classes (to .pmc > files or something). Yuval explored a lot of these ideas (and a more > compile-able meta-model) in his MO experiement, but that remains just a > research > project at this point. Yuval and I are still pondering this along with the > rest > of the Moose crew, so have faith. > > - Stevan