On 25/02/2008, Stefan Marr <[EMAIL PROTECTED]> wrote: > Hi, > > there is a lot of discussion going on about how traits should actually > work in PHP. > > Currently, one of the main challenges seams to be to agree on a suitable > mechanism to avoid breaking traits and there behavior. > Eventually, there seams to be a large discomfiture on the excluding of > methods and the interweaving of methods from different traits. > > I can agree on the opinion, that a unconditional exclude mechanism could > accidentally break traits. > But, I really do like the notion to be able to interweave traits and > compose something new from it, which results in an overlapping construct > using the appropriate methods for a concrete problem. Well, this implies > traits are not units of black-boxed reuse. They do act really > fine-grained and will require the knowledge about the used methods. > > Therefore, remove/exclude is bad, we need to get rid of it. > There are some thoughts about aliasing. It seams to be not the > natural/closest solution. Renaming semantics would be more natural, but > it implies an exclude of the old method, too. Thus, renaming could > accidentally breaking a trait. Eventually, renaming needs to be avoided, > too. > > Ok, lets get a step back and recall what traits have to achieve. > > Traits try to be a construct to allow the reuse of a group of semantical > related methods. > They do not try to replace inheritance or the delegation patter. They > are still valid means to reuse "complex behavior and state" things. > Instead, the way to go with traits should be to reuse a small, > predominantly independent (but semantically related) number of methods > not justifying to build a full fledged class from them. Use traits to > build a class from them, which adds some additional semantics/behavior > to the set of methods got from the traits and build a complete blue > print for objects from it. > > The main thing here seams to be that the current proposal does not > fulfill the claim to combine the traits properly in the case of > conflicts. Instead, there is a lot of potential to break the traits > behavior. > > Let's try to find a notation where the traits are combined and conflicts > are solved upfront, before being applied to the class. (This is even the > way the implementation works right now.) > > To get rid of exclude and rename I would like to propose the following: > > //Example from the RFC with the cross-over conflict to be solved > trait A { > public function smallTalk() { > echo 'a'; > } > public function bigTalk() { > echo 'A'; > } > } > > trait B { > public function smallTalk() { > echo 'b'; > } > public function bigTalk() { > echo 'B'; > } > } > > //here the new notion of combing traits and resolving conflicts upfront > class Talker { > use A, B { > B::smallTalk instead A::smallTalk; > A::bigTalk instead B::bigTalk; > A::bigTalk as talk; > } > } > > > The new ``use`` is defined as use with a list of traits to be included > into the class. > Since the exclude is not appropriated, conflicts could be solved a lot > more explicitly with the new ``instead`` keyword. > It has be read as: use B::smallTalk instead of A::smallTalk, which > solves the conflict explicitly and avoids the need for an exclude > operator with the power to exclude arbitrary methods. > If more traits are combined it could look like ``A:foo instead B::foo, > C::foo;`` > > To be able to reuse a method which is excluded this way the ``as`` > keyword can be used. > Read it like this: use A::bigTalk as talk in the class. > > Think with this, it is not possible to remove a method somehow. > This could be even superior to the "hidding" thing and the notion of > "trait-local" methods since everything/any part of the semantics is > explicitly available in the notation. This has not been the case for > other notations so far. The trait-local things are nice, but complex and > I would prefer to avoid them, since the proposed traits have a very > clean and simple semantics. May be we could introduce them as addition > in a later release.
I like this mechanism. This really does seem to be what I would use. It also treats developers with a bit of respect that they understand what they are doing and as such doesn't need to provide a wasteful safety net. No magic. A question though (and I don't have any sort of examples to explain this better, so I hope you all follow). If there are common names to methods in multiple traits (assume third party libraries), and you one trait::method over another (A::bigTalk instead B::bigTalk;), this will surely break the b trait? B trait may well use its own bigTalk method. Instead it is going to end up using A's bigTalk. A "way" (more of an idea than a real solution and the syntax is wild here) would be to support a "namespace" concept. trait DTalker { function dTalk() { echo 'D'; } } trait CTalker requires DTalker { function cTalk() { $this->dTalk(); } class Talker { use ATalker as A, BTalker as B, CTalker function usingTraits() { $this->A::bigTalk(); $this->B::smallTalk(); $this->CTalker::cTalk(); // Maybe these are all the same method. $this->CTalker::DTalker::dTalk(); $this->CTalker::dTalk(); $this->dTalk(); } } Traits as namespaces would solve the issue of conflict in the class Talker (you would have to explicitly say which trait the method came from. I don't know if this can all be resolved at compile time. Surely the use of call_user_func() and others would impact somehow. If trait C requires trait D, then this may lead to longer namespaces - but from my understanding the purpose of namespaces is to resolve collisions, so it cannot be avoided when there are collisions. (Though my example doesn't collide - but that's not the point). I hope this makes some sense. Richard. -- ----- Richard Quadling Zend Certified Engineer : http://zend.com/zce.php?c=ZEND002498&r=213474731 "Standing on the shoulders of some very clever giants!" -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php