Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:51236 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 91522 invoked from network); 6 Jan 2011 22:50:21 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 6 Jan 2011 22:50:21 -0000 Authentication-Results: pb1.pair.com header.from=php@stefan-marr.de; sender-id=unknown Authentication-Results: pb1.pair.com smtp.mail=php@stefan-marr.de; spf=permerror; sender-id=unknown Received-SPF: error (pb1.pair.com: domain stefan-marr.de from 81.20.134.149 cause and error) X-PHP-List-Original-Sender: php@stefan-marr.de X-Host-Fingerprint: 81.20.134.149 vps-1012701-4512.united-hoster.de Received: from [81.20.134.149] ([81.20.134.149:49192] helo=vps-1012701-4512.united-hoster.de) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id C7/AB-25120-B27462D4 for ; Thu, 06 Jan 2011 17:50:20 -0500 Received: from 94-224-217-64.access.telenet.be ([94.224.217.64] helo=[192.168.0.13]) by vps-1012701-4512.united-hoster.de with esmtpsa (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.72) (envelope-from ) id 1Payet-00027Y-Cf; Thu, 06 Jan 2011 23:50:16 +0100 Mime-Version: 1.0 (Apple Message framework v1082) Content-Type: text/plain; charset=us-ascii In-Reply-To: <4D206CA4.6060004@yahoo.com.au> Date: Thu, 6 Jan 2011 23:50:09 +0100 Cc: internals@lists.php.net Content-Transfer-Encoding: quoted-printable Message-ID: <767E5516-E475-46E8-AE5C-9406D90881D7@stefan-marr.de> References: <4D206CA4.6060004@yahoo.com.au> To: Ben Schmidt X-Mailer: Apple Mail (2.1082) Subject: Re: [PHP-DEV] Extensions to traits From: php@stefan-marr.de (Stefan Marr) Hi Ben: On 02 Jan 2011, at 13:16, Ben Schmidt wrote: > While it's still in the pre-release stage, though, I would like to put > in a vote for the assignment syntax: I think it is a lot easier to = read > and understand than the 'insteadof' syntax. The reason to go with insteadof is that the assignment syntax hides = changes that might cause problems. Thus, when you change any of the traits participating in a composition = in a way that a conflict would be introduced, the assignment syntax is = hiding this. With the insteadof syntax you are actually forced to = reevaluate whether your code still makes sense and include the offending = change explicitly. > There are two limitations of traits in their current implementation = for > which I would like to propose extensions. The first limitation is that > traits can very easily break, particularly when methods are omitted = from > classes in which the rest of the trait is used Ehm, not sure I follow what you are getting at. One thing to emphasize here is the explicit design choice to use the = insteadof. This does not only have the mentioned benefit of making problematic = changes in the traits hierarchy explicit, but the second reason to go = with this design was the wish to have a 'exclude' operator without = actually having a full-exclude operator. Thus, there is no way that you = can leave out arbitrary methods from a trait. That means, you cannot build compositions which suddenly miss certain = expected method implementations. Well, of course, you can always build bugs into the code, but that is = not different from the standard situation. You can always call arbitrary = method names that just do not exist. Traits do not protect you from = that. But the current design, protects you from explicitly allowing you = to shot yourself in the foot. > , or shadowed by method > definitions in the class proper. The second limitation is that the = trait > overriding semantics are impoverished and needlessly restrictive. Hm, don't understand you here either. I needed to look up what = impoverished actually means, you are not insulting me here, right? Just = kidding ;) > Incorrect method calls spring from the way trait methods can be = omitted > from classes where the rest of the trait is used, or shadowed by = methods > defined in the class proper. In either of these scenarios, any call in = a > trait to such a method may not call the method that was originally > intended--they may fail, or they may call a different method, with > unpredictable results. Of course, sometimes such a behaviour is > desirable, if writing a trait which communicates with the rest of the > class by means of method calls, yet provides a fallback methods in = case > the class author does not wish to provide such methods. However, when = it > is not intended, this could lead to incorrect and = difficult-to-pinpoint > behaviour. Ok, now I see what you are getting at. And my answer to that is: If you require your trait to guarantee a = certain non-trivial invariants, then well, what you are actually doing = is something which should become a class with all its benefits. Traits are not intended to replace classes as a mechanism to structure = code, but they should supplement it. However, I am open to votes on these things since I do not have any = reason to believe that my standpoint is especially useful or superior, = thats just how I understand what traits are useful for. > trait ErrorReporting { > public function error($message) { > $this->print($message); > } > private function print($message) { > fputs($this->output,$message."\n"); > } > } >=20 > class Printer { > use ErrorReporting; > public $output=3Dnull; > public function print($document) { > /* Send the document to the printer--$this->output. */ > /* ... */ > if (there_was_an_error()) { > $this->error("printing failed"); > } > /* ... */ > } > } Ok, to summarize the example, you get a recursion because there is a = naming problem, i.e., incompatibility between the used trait and the = composing class. > No error or warning will be > generated, but the class will not work as intended; probably it will > infinitely recurse; a nasty problem to track down. > Furthermore, even if the incorrect method call didn't occur, there = would > be data-sharing problems, as both the ErrorReporting trait and the > class' print() function make use of the $output data member, > unintentially sharing data. Well, short answer: it is compiler-assisted copy-and-past, why isn't = that trait just providing the glue that gets your class the necessary = functionality to use a proper ErrorReporting class? Sorry, I know not a really helpful answer, but I hope that examples = shows how I see traits. They are for reusing code in situations where the other concepts just = break down. Not meant to replace those. >=20 > Proposal > -------- >=20 > I suggest these problems should be solved from two angles. Firstly, > additional warnings should be triggered to alert the programmer to the > problems, and secondly, the traits mechanism should be extended to = allow > more desirable behaviours to be programmed. >=20 > Warnings > - - - - >=20 > To avoid silent unintended shadowing, I suggest issuing a warning when = a > conflict between trait and class methods occurs. So this would trigger > a warning: >=20 > trait SaySomething { > public function sayIt() { > echo "Something\n"; > } > } > class Sayer { > use SaySomething; > public function sayIt() { > echo "Hello world!\n"; > } > } Ok, well, we could see the actual class body as another trait, and = require it to follow the same composition rules, and that way make = require the programmer to use insteadof in such a case. In return that would mean, that traits are not part of the inheritance = chain at all anymore. Thus, first is the inheritance chain used to build up the implementation = of a class, and afterwards all the traits are composed, while the = original class is seen as another trait. That idea has certainly something to it. >=20 > use SaySomething { > sayIt =3D null; > } > use SaySomething { > unset sayIt; > } > use SaySomething { > sayIt =3D SaySomething::sayIt; > } I would reject that based on the arguments from the beginning of the = email. Ok, thats enough for this email. I will come back to the extension in a later email. Thanks for the proposals Stefan --=20 Stefan Marr Software Languages Lab Vrije Universiteit Brussel Pleinlaan 2 / B-1050 Brussels / Belgium http://soft.vub.ac.be/~smarr Phone: +32 2 629 2974 Fax: +32 2 629 3525