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