Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:35564 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 94455 invoked by uid 1010); 18 Feb 2008 23:01:02 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 94440 invoked from network); 18 Feb 2008 23:01:02 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 18 Feb 2008 23:01:02 -0000 Authentication-Results: pb1.pair.com header.from=dz@bitxtender.com; sender-id=unknown Authentication-Results: pb1.pair.com smtp.mail=dz@bitxtender.com; spf=permerror; sender-id=unknown Received-SPF: error (pb1.pair.com: domain bitxtender.com from 80.237.132.12 cause and error) X-PHP-List-Original-Sender: dz@bitxtender.com X-Host-Fingerprint: 80.237.132.12 wp005.webpack.hosteurope.de Received: from [80.237.132.12] ([80.237.132.12:49338] helo=wp005.webpack.hosteurope.de) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id B1/B0-23568-C2E0AB74 for ; Mon, 18 Feb 2008 18:01:01 -0500 Received: from xdsl-87-79-62-95.netcologne.de ([87.79.62.95] helo=Wombook.lan); authenticated by wp005.webpack.hosteurope.de running ExIM using esmtpsa (TLSv1:RC4-SHA:128) id 1JREbi-0007VT-U6; Mon, 18 Feb 2008 23:37:07 +0100 Cc: php-dev List Message-ID: To: In-Reply-To: <001c01c87264$3c01b4e0$b4051ea0$@de> Content-Type: text/plain; charset=US-ASCII; format=flowed; delsp=yes Content-Transfer-Encoding: 7bit Mime-Version: 1.0 (Apple Message framework v919.2) Date: Mon, 18 Feb 2008 23:37:06 +0100 References: <001c01c87264$3c01b4e0$b4051ea0$@de> X-Mailer: Apple Mail (2.919.2) X-bounce-key: webpack.hosteurope.de;dz@bitxtender.com;1203375660;1f143dc6; Subject: Re: [PHP-DEV] RFC: Traits for PHP From: dz@bitxtender.com (=?ISO-8859-1?Q?David_Z=FClke?=) Fantastic. Nice RFC, nice explanation, nice design - I love it. Can I +1 already? :) David Am 18.02.2008 um 20:27 schrieb : > Hi, > > during last six months I've studied a language construct called > Traits. > It is a construct to allow fine-grained code reuse and in my opinon > this would be a nice feature for PHP, which I did like to propose > here. > The following RFC deals with the questions what Traits are, how they > are > used, why they are usefull and how they do look like in PHP. > A patch implementing this new language construct is available, too. > > Thank you for your attention and I'm looking forward to hear your > comments > :) > > Kind Regards > Stefan > > > > Request for Comments: Traits for PHP > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > > :HTML: http://www.stefan-marr.de/artikel/rfc-traits-for-php.html > > ... contents:: > > This RFC will discuss at first the motivation for Traits describing > the > rationals > and presenting a short real world use case. The main part will > describe the > concept of Traits in detail using the syntax for Traits implemented > in a > patch > which is part of this proposal. In the end, the URL of the patch and > additional resources about Traits are given. > > Introduction > ============ > > *Traits* is a mechanism for code reuse in single inheritance > languages such > as PHP. A Trait is intended to reduce some limitations of single > inheritance > by enabeling a developer to reuse sets of methods freely in several > independent > classes living in different class hierarchies. > The semantics of the combination of Traits and classes is defined in > a way, > which reduces complexity and avoids the typical problems associated > with > multiple > inheritance and Mixins. > > They are recognized for their potential in supporting better > composition > and reuse, hence their integration in newer versions of languages > such as Perl 6, Squeak, Scala, Slate and Fortress. > Traits have also been ported to Java and C#. > > > Why do we need Traits? > ---------------------- > > Code reuse is one of the main goals that object-oriented languages > try to > achieve > with inheritance. Unfortunately, single inheritance often forces the > developer > to take a decision in favor for either code reuse *or* conceptual > clean > class > hierarchies. To achieve code reuse, methods have either to be > duplicated or > to be moved near the root of the class hierarchy, but this hampers > understandability and maintainability of code. > > To circumvent this problems multiple inheritance and Mixins have been > invented. > But both of them are complex and hard to understand. PHP5 > has been explicitly designed with the clean and successful model of > Java in > mind: single inheritance, but multiple interfaces. This decision has > been > taken > to avoid the known problems of for example C++. > Traits have been invented to avoid those problems, too. They enable > designer > to build > conceptually clean class hierarchies without the need to consider > code reuse > or > complexity problems, but focusing on the real problem domain and > maintainability > instead. > > Traits: A Mechanism for Fine-grained Reuse > ========================================== > > A Trait is a unit of reuse much like a class, but only intended to > group > functionality in a fine-grained and consistent way. It is not > possible to > instantiate a Trait on its own. It is an addition to traditional > inheritance > and enables horizontal composition of behavior. > > The following code illustrates the current implementation of an > extended > version of the PHP reflection API which provides detailed access to > doc > comment > blocks. > > ReflectionMethod and ReflectionFunction are classes from the > reflection API > and > have to be extended with exactly the same code. In some situations it > would be possible to add a common base class, but in this case it is > impossible, because the extended classes are not under our control, > i.e., > they > are implemented in third party code or even in C, like it is the > case here. > :: > > class ezcReflectionMethod extends ReflectionMethod { > /* ... */ > function getReturnType() { /*1*/ } > function getReturnDescription() { /*2*/ } > /* ... */ > } > > class ezcReflectionFunction extends ReflectionFunction { > /* ... */ > function getReturnType() { /*1*/ } > function getReturnDescription() { /*2*/ } > /* ... */ > } > ?> > > With Traits it is possible to refactor this redundant code out. > :: > > trait ezcReflectionReturnInfo { > function getReturnType() { /*1*/ } > function getReturnDescription() { /*2*/ } > } > > class ezcReflectionMethod extends ReflectionMethod { > use ezcReflectionReturnInfo; > /* ... */ > } > > class ezcReflectionFunction extends ReflectionFunction { > use ezcReflectionReturnInfo; > /* ... */ > } > ?> > > This is just a small example of what Traits are useful for. > The next sections will discuss on more advanced techniques and > describe how > the > current implementation of Traits for PHP works. > > The Flattening Property > ----------------------- > > As already mentioned, multiple inheritance and Mixins are complex > mechanisms. > Traits are an alternative which have been designed to impose no > additional semantics on classes. Traits are only entities of the > literal > code > written in your source files. There is no notion about Traits at > runtime. > They are used to group methods and reuse code and are totally > flattened > into the classes composed from them. It is almost like a language > supported > and > failsafe copy'n'paste mechanism to build classes. > > Precedence Order > """""""""""""""" > > Flattening is achieved by applying some simple rules on the > composition > mechanism. Instead of implementing a fancy and awkward algorithm to > solve > problems, the entire control about the composition is left in the > hand of > the > developer and fits nicely into the known inheritance model of PHP. > The following examples illustrate the semantics of Traits and their > relation > to methods defined in classes. > :: > > class Base { > public function sayHello() { > echo 'Hello '; > } > } > > trait SayWorld { > public function sayHello() { > parent::sayHello(); > echo 'World!'; > } > } > > class MyHelloWorld extends Base { > use SayWorld; > } > > $o = new MyHelloWorld(); > $o->sayHello(); // echos Hello World! > ?> > > As shown in the above code, an inherited method from a base class is > overridden > by the method inserted into ``MyHelloWorld`` from the ``SayWorld`` > Trait. > The behavior is the same for methods defined in the ``MyHelloWorld`` > class. > The precedence order is that methods from the current class override > Trait > methods, > which in return override methods from the base class. > :: > > trait HelloWorld { > public function sayHello() { > echo 'Hello World!'; > } > } > > class TheWorldIsNotEnough { > use HelloWorld; > public function sayHello() { > echo 'Hello Universe!'; > } > } > > $o = new TheWorldIsNotEnough(); > $o->sayHello(); // echos Hello Universe! > ?> > > Multiple Traits Usage > """"""""""""""""""""" > > To keep things simple in the beginning, there has only one Trait > being used > at > a time, but obviously a class could use multiple Traits at the same > time. > :: > > trait Hello { > public function sayHello() { > echo 'Hello '; > } > } > > trait World { > public function sayWorld() { > echo ' World'; > } > } > > class MyHelloWorld { > use Hello; > use World; > public function sayExclamationMark() { > echo '!'; > } > } > > $o = new MyHelloWorld(); > $o->sayHello(); > $o->sayWorld(); > $o->sayExclamationMark(); > // Results eventually in: Hello World! > > Conflict Resolution > """"""""""""""""""" > > But now a problem will occur, if different Traits provide methods > with the > same name. > :: > > trait A { > public function smallTalk() { > echo 'a'; > } > public function bigTalk() { > echo 'A'; > } > } > > trait B { > public function smallTalk() { > echo 'b'; > } > public function bigTalk() { > echo 'B'; > } > } > ?> > > Both classes have to be used in a class named ``Talker``. Multiple > inheritance > and Mixins define an algorithm to resolve this conflict. Traits don't. > Conflicts > aren't solved implicitly by any kind of precedence. Instead, to avoid > implicit > complexity, the developer has full control over class composition. > :: > > class Talker { > use A; > use B; > } > ?> > > In case of the above definition of ``Talker``, PHP will show a > notice that > there > have been conflicts and name the methods ``smallTalk()`` and > ``bigTalk()`` > as the reason of this conflict. Therefore, neither of the given > implementations > will be available in the class. > > Instead, the developer can exactly define which methods are used and > how the > conflict is resolved. > :: > > class Talker { > use A { !smallTalk } > use B { !bigTalk } > } > ?> > > This definition will result in the exclusion of ``smallTalk()`` from > the > Trait A > and ``bigTalk()`` from Trait B. Therefore, the resulting class > Talker would > echo ``'b'`` for ``smallTalk()`` and ``'A'`` for ``bigTalk().`` > But simple exclusion of methods is not the best choice for all > situations. > :: > > class Talker { > use A { !smallTalk } > use B { !bigTalk, talk => bigTalk } > } > ?> > > Beside the exclusion an alias operation is available, too. This alias > operation, notated like a ``key => value`` for arrays even has a > similar > semantics like the array notation. The definition ``talk => bigTalk`` > lets the new name ``talk`` refer to the method body of ``bigTalk`` > of the Trait B. The resulting ``Talker`` class will consist of > following > three methods: > > * ``bigTalk() { echo 'A'; }`` > * ``smallTalk() { echo 'b'; }`` > * ``talk() { echo 'B'; }`` > > Since the alias operation adds a new name to an existing method > body, the > ``bigTalk`` method still has to be excluded. Otherwise, PHP would > print > a notice that two methods from Traits have a conflict and are > excluded. > Aliasing is not renaming and references in methods to a given method > name > aren't changed either. On the first look this may sound strange, but > it > provides the opportunity to build Traits and even hierarchies of > Traits > which > fit together very well. > > Traits Composed from Traits > """"""""""""""""""""""""""" > > Not explicitly mentioned jet, but implied by the flattening property > is the > composition of Traits from Traits. > Since Traits are fully flattened away at compile time it is possible > to use > Traits to compose Traits without any additional impact on the > semantics. > The following code illustrates this:: > > trait Hello { > public function sayHello() { > echo 'Hello '; > } > } > > trait World { > public function sayWorld() { > echo 'World!'; > } > } > > trait HelloWorld { > use Hello; > use World; > } > > class MyHelloWorld { > use HelloWorld; > } > > $o = new MyHelloWorld(); > $o->sayHello(); > $o->sayWorld(); > // Results eventually in: Hello World! > ?> > > Traits itself can take part in arbitrary compositions, but Traits > are not > part > of the inheritance tree i.e., it is not possible to inherit from a > Trait to > avoid confusion and misuse of Traits. > > Traits Semantics Summarized > --------------------------- > > 1. Traits do not add runtime semantics, they only take part in the > process > of > building a class. > 2. Traits integrate into the precedence order of method overriding. > 3. To avoid complexity, conflicts between Trait methods have to be > solved > explicitly. Otherwise a notice is generated and the conflicting > methods > are excluded. > 4. Specific methods can be excluded from a composition to handle > conflicts. > 5. Aliases can be defined for methods to enable reuse of conflicting > methods. > 6. Traits can be composed from Traits. > > As a result of this semantics, at runtime, classes build using > Traits are > not distinguishable > from classes not using Traits but traditional code duplication > instead. > Semantics of ``parent`` and ``$this`` hasn't changed, too. Used in a > Trait > method, they behave exactly the same as if the method has been > defined in > the > class directly. > > Visibility and Interfaces > ------------------------- > > Visibility modifiers have not been discussed so far. Since Traits > are meant > as > units of reuse, modifiers should be changeable easily in the context > of a > composed class. Therefore, the aliasing operation is able to change > the > visibility modifier of a method, too. > :: > > trait HelloWorld { > public function sayHello() { > echo 'Hello World!'; > } > } > > class MyClass1 { > use HelloWorld { protected sayHello } > } > > class MyClass2 { > use HelloWorld { private doHelloWorld => sayHello } > } > ?> > > The abstract and final modifiers are supported, too. Abstract > methods in > Traits are commonly used to define requirements a Trait needs to have > implemented by a class. The static modifier is not supported, > because it > would > change the methods semantics and references to ``$this`` would break. > > Another important feature of PHP is the support of interfaces. A > often used > metaphor to describe Traits is *Traits are interfaces with > implementation*. > Traits can be utilized to provide the implementation for a specific > interface > and since an interface is a guarantee that some methods are > available it > fits > in the concept of Traits which provides those methods very well. > > To underpin this relationship, it is possible to declare that a Trait > implements an interface like this:: > > interface IHello { > public function sayHello(); > } > > trait SayHello implements IHello { > public function sayHello() { > echo 'Hello World!'; > } > } > > class MyHelloWorld { > use SayHello; > } > > $o = new MyHelloWorld(); > var_dump($o instanceof IHello); // bool(true) > > If a Trait implements an interface, this definition is propagated to > the > class > using the Trait. Therefore, it is possible to provide > implementations for an > interface > and reuse them in different classes. > > Proposal and Patch > ================== > > This Request for Comments proposes a new language feature for PHP > named > Traits. > Traits are a nice approach to enhance the capabilities to design > conceptual > consistent class hierarchies and avoid code duplication. > > The patch against the PHP_5_2 branch is available at > http://toolslave.net/snapshots/traits/traits.patch > The written test cases are located here: > http://toolslave.net/snapshots/traits/traits-tests.zip > Additionally, the SVN repo used for developing this patch is located > at > https://instantsvc.svn.sourceforge.net/svnroot/instantsvc/branches/php-exten > sion/traits-php/ > > Alternative Syntax Proposals > ---------------------------- > > This section collects proposals for alternative Traits syntaxes. > > Traits Use Definition in the Class Header > """"""""""""""""""""""""""""""""""""""""" > > Instead of declaring the Trait composition in the class body, it > could be > defined in the class prologue like this:: > > trait Hello { > public function sayHello() {} > } > > > class MyHelloWorld extends BaseClass > uses Hello (hello => sayHello, !sayHello) > { > public function foo() {} > } > ?> > > The drawback of this notation is the implied notation of Traits as > some kind > of > a type changing construct. Since they do not influence the type as > their > major > feature, this notion would be misleading. Furthermore, this notation > seams > to > have readability problems. Complex compositions are not as clearly > arranged > as > they are with the *In-Body* notation. > A patch implementing this notation is available at: > http://toolslave.net/snapshots/traits/traits-head-syntax.patch > > > More about Traits > ----------------- > > As already mentioned, Traits is not a totally new concept, but the > semantics > used in this proposal has been fully defined at first in 2003. For > scientific > information and papers about Traits > http://www.iam.unibe.ch/~scg/Research/Traits/ > is a good starting point. Since it isn't a purely academic concepts, > there > are > already languages supporting Traits out there. Squeak, Perl6, Scala, > Slate, > Fortress and even for C#/Rotor implementation are available. > > A detailed technical report has been published at > http://www.iam.unibe.ch/~scg/Archive/Papers/Duca06bTOPLASTraits.pdf > It explains Traits and gives some formal proves about the soundness of > Traits, too. > > Last but not least, in this Phd thesis > http://www.iam.unibe.ch/~scg/Archive/PhD/schaerli-phd.pdf > two case studies have been publish illustrating the benefits Traits > are > providing. > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >