Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:35802 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 57919 invoked by uid 1010); 25 Feb 2008 21:37:03 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 57904 invoked from network); 25 Feb 2008 21:37:03 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 25 Feb 2008 21:37:03 -0000 Authentication-Results: pb1.pair.com header.from=rquadling@googlemail.com; sender-id=pass; domainkeys=bad Authentication-Results: pb1.pair.com smtp.mail=rquadling@googlemail.com; spf=pass; sender-id=pass Received-SPF: pass (pb1.pair.com: domain googlemail.com designates 209.85.146.176 as permitted sender) DomainKey-Status: bad X-DomainKeys: Ecelerity dk_validate implementing draft-delany-domainkeys-base-01 X-PHP-List-Original-Sender: rquadling@googlemail.com X-Host-Fingerprint: 209.85.146.176 wa-out-1112.google.com Received: from [209.85.146.176] ([209.85.146.176:18216] helo=wa-out-1112.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 1F/E4-29498-EF433C74 for ; Mon, 25 Feb 2008 16:37:03 -0500 Received: by wa-out-1112.google.com with SMTP id l24so2051358waf.17 for ; Mon, 25 Feb 2008 13:36:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=gamma; h=domainkey-signature:received:received:message-id:date:from:reply-to:to:subject:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references; bh=Ti4HFXUddo0nCNP2G67OsA5nD1whcqfh1m7gZUS9I3c=; b=ELNzMjRpYbvXkxqY7mc+IrUZFiOs2El82KkXJ8H9Z0lj70OZdOVd+erwOWalptvgjXpjvVWE1AK6XLkB+gpZbb4Kr+vlJYBp9usp0ZFFdFqqWCn6vSJiOiIv5Oe0WjzQ7TXnhCnfCmhwOeZyfCP6Iaw0uhw0nhaQ2w9O9tu1Gtw= DomainKey-Signature: a=rsa-sha1; c=nofws; d=googlemail.com; s=gamma; h=message-id:date:from:reply-to:to:subject:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references; b=EqgS4FwhCz+GRGsoOAP6F10WyMGK7qZZeUrWRpXwSSMVaIOD3M8+RicJzlJf+dtL0U/BLaPi2pU5pHQdlhZqPc4A3t9DgQiIjCvGeP9ForNImZBlaZ82IW5FsuwKe9g4emFhxP5FgUBfsRfx0kz6b59lse9VAv9izP5yf8QlP/I= Received: by 10.114.120.1 with SMTP id s1mr4292945wac.107.1203975419670; Mon, 25 Feb 2008 13:36:59 -0800 (PST) Received: by 10.114.209.15 with HTTP; Mon, 25 Feb 2008 13:36:59 -0800 (PST) Message-ID: <10845a340802251336l4ec51e2bg493f0bd8e4684264@mail.gmail.com> Date: Mon, 25 Feb 2008 21:36:59 +0000 Reply-To: RQuadling@GoogleMail.com To: php@stefan-marr.de, "Internals Mailing List" In-Reply-To: <47C317F4.2080301@stefan-marr.de> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit Content-Disposition: inline References: <47C317F4.2080301@stefan-marr.de> Subject: Re: [PHP-DEV] How to build a real Trait thing without exclusion and renaming From: rquadling@googlemail.com ("Richard Quadling") On 25/02/2008, Stefan Marr 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!"