Re: [PHP-DEV] Grafts, Traits, horizontal reuse
On Saturday 18 April 2009 12:57:19 pm Stefan Marr wrote: Hi Stan, I see this in a much simpler fashion. Treat traits as a preprocessor step semantically. Internally, trait methods on multiple classes may point to the same method to save resources, but in my opinion there's no need to complicate matter by introducing new resolution rules, scopes, and so on. The way I see it: 1) Property/Method name conflicts on trait/class, within the class including the trait raises Fatal Error. Well, with methods this is ok, but properties are not Java fields which are known at compile time, so it is not that easy. Even when they are known beforehand things are more complicated. State is usually even less composable than behavior/methods. 3) There's a single space for a class property and its trait properties, so access works as if it was all class properties. trait Counter { var $value; public function inc() { $this-value++; } ... } trait Color { var $hue; var $saturation; var $value; public function getRGB() { /* ... */} ... } class MyClass { use Counter, Color; } Ok, you could argue that you than will have to refactor your property names in your state. But then you will break other traits. Even worth, this trait is defined in a widely used framework and your breaking other peoples code just by changing implementation details which should not even be visible to your users. I do not think that this simple model is practicable. Unfortunately, it is implied by the current state-less proposal, if we do not forbid any access to properties inside of trait methods (which sounds like a stupid idea to me). :( Regards Stefan Feedback? Earlier in the thread, someone suggested making properties entirely restricted to their trait, not any using class. If you want access to a trait's property, use an accessor and be done with it. That way it doesn't matter if different traits use the same property names since they'll always be resolved relative to the method that's using them. Is there an implementation reason why that would not be a feasible solution? From a developer experience perspective it seems like a reasonable approach. Also, at the risk of scope creep I will ask if any sort of runtime knowledge is being considered? That is, would there be a way to at runtime get a list of all traits that a given class is using, or access them separately? Would that be a possible way around the question of duplicate method names? (Vis, reimplement the conflicting method and then specify which of the trait methods you want to use by calling it, or possibly calling both of them. That would allow for potentially interesting use cases, and force the resolution logic onto the implementer rather than trying to come up with the perfect resolution rules for all case. Eg: trait Foo1 { public function foo() {} } trait Foo2 { public function foo() {} } class Bar { use Foo1, Foo2; public function foo() { // Without this, we get a parse error return $this-Foo1-foo(); // or return $this-Foo2-foo(); // or foreach ($this-traits as $trait) { $return[] = $trait-foo(); } return implode(',', $return); // or whatever makes sense for your use case. } } -- Larry Garfield la...@garfieldtech.com -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Grafts, Traits, horizontal reuse
Hi Larry, Also, at the risk of scope creep I will ask if any sort of runtime knowledge is being considered? That is, would there be a way to at runtime get a list of all traits that a given class is using, or access them separately? well, the reflection API will be extended to be able to reflect about traits, too. But beside this, there is no notion of traits at runtime. Would that be a possible way around the question of duplicate method names? (Vis, reimplement the conflicting method and then specify which of the trait methods you want to use by calling it, or possibly calling both of them. That would allow for potentially interesting use cases, and force the resolution logic onto the implementer rather than trying to come up with the perfect resolution rules for all case. That is already possible by means of aliasing as described in the RFC [1]. You can provide different aliases for the conflicting methods and then decide how to proceed in the method implemented in the composing class by calling the aliases. Best regards Stefan [1] http://wiki.php.net/rfc/horizontalreuse -- Larry Garfield la...@garfieldtech.com -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php -- Stefan Marr Programming Technology Lab Vrije Universiteit Brussel Pleinlaan 2 / B-1050 Brussels / Belgium http://prog.vub.ac.be/~smarr -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Grafts, Traits, horizontal reuse
The question here is how to handle property accesses, in particular accesses to unspecified properties. I actually would expect to have a lookup mechanism which first looks in the trait, and if the property is not found there, its going to the object. I expect this behavior, because it is similar to what we have with inheritance and properties defined by a superclass. If a property is not jet defined, I would expect it to be created in the most inner scope, like local variables. On the other hand, I also would expect, as in inheritance, properties to be found defined by super classes, or the class which defines the composition. But this only my intuitive solution, so this could of course be specified different. Best regards Stefan Hi, I see this in a much simpler fashion. Treat traits as a preprocessor step semantically. Internally, trait methods on multiple classes may point to the same method to save resources, but in my opinion there's no need to complicate matter by introducing new resolution rules, scopes, and so on. The way I see it: 1) Property/Method name conflicts on trait/class, within the class including the trait raises Fatal Error. 2) Extending classes can override the property/method, unless it's a final method, just like as if they override normal parent class property/method. 3) There's a single space for a class property and its trait properties, so access works as if it was all class properties. Feedback? Regards, Stan Vassilev -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Grafts, Traits, horizontal reuse
Hi Stan, I see this in a much simpler fashion. Treat traits as a preprocessor step semantically. Internally, trait methods on multiple classes may point to the same method to save resources, but in my opinion there's no need to complicate matter by introducing new resolution rules, scopes, and so on. The way I see it: 1) Property/Method name conflicts on trait/class, within the class including the trait raises Fatal Error. Well, with methods this is ok, but properties are not Java fields which are known at compile time, so it is not that easy. Even when they are known beforehand things are more complicated. State is usually even less composable than behavior/methods. 3) There's a single space for a class property and its trait properties, so access works as if it was all class properties. trait Counter { var $value; public function inc() { $this-value++; } ... } trait Color { var $hue; var $saturation; var $value; public function getRGB() { /* ... */} ... } class MyClass { use Counter, Color; } Ok, you could argue that you than will have to refactor your property names in your state. But then you will break other traits. Even worth, this trait is defined in a widely used framework and your breaking other peoples code just by changing implementation details which should not even be visible to your users. I do not think that this simple model is practicable. Unfortunately, it is implied by the current state-less proposal, if we do not forbid any access to properties inside of trait methods (which sounds like a stupid idea to me). :( Regards Stefan Feedback? Regards, Stan Vassilev -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php -- Stefan Marr Programming Technology Lab Vrije Universiteit Brussel Pleinlaan 2 / B-1050 Brussels / Belgium http://prog.vub.ac.be/~smarr -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Grafts, Traits, horizontal reuse
trait Counter { var $value; public function inc() { $this-value++; } ... } trait Color { var $hue; var $saturation; var $value; public function getRGB() { /* ... */} ... } class MyClass { use Counter, Color; } Ok, you could argue that you than will have to refactor your property names in your state. But then you will break other traits. Even worth, this trait is defined in a widely used framework and your breaking other peoples code just by changing implementation details which should not even be visible to your users. I do not think that this simple model is practicable. Unfortunately, it is implied by the current state-less proposal, if we do not forbid any access to properties inside of trait methods (which sounds like a stupid idea to me). :( Regards Stefan Hi, Since the expectancy of a trait is it'll be used in many other classes horizontally, I wouldn't think people will start taking generic names in traits as they do in normal classes. I'd personally expect this naming convention more likely: trait Counter { protected $counterValue; } trait Observable { protected $observableListeners; } And so on. The benefit is it's easy to implement, understand, and use. However if this is not acceptable to many, and we could live with the complication of it, the best idea for trait property access I suppose would be this: trait Observable { protected $listeners; } class Any { use Observable; function accessTraitProperty() { var_dump($this-Observable-listeners); } } Hence namespacing trait state into an automatically created object of the same name, and we're done. On the other said, a all traits could have an automatic property owner, which gives it access to the class state/properties. Regards, Stan Vassilev -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Grafts, Traits, horizontal reuse
Hi Tom, On 15 Apr 2009, at 16:13, Tom Boutell wrote: PHP needs real horizontal reuse, no question. Looking forward to get this discussion running once again after 5.3 is released :) My first reaction to traits was positive - it's simple and simple is good. However I'm very concerned about the implications of not allowing state. In the real world people are going to want to do horizontal reuse that involves state. So they will work around it. I share you're concerns about state. Even though, I would like to keep Traits as simple as possible. From my perspective, it would be possible to introduce a full-grained language concept for traits like proposed in the literature [1]. But, it is quite complex. On the other hand, this language constructs would be only used rarely, and in this rare situations, it would be probably beneficial to have them at hand. Merging attributes/properties of traits, aliasing and so on. For the sake of simplicity, we might discuss a very basic solution. It would be possible to introduce trait-local state only. Thus, all properties defined in a trait are only available within methods of the same trait, no other operations are able to access these properties. How ever, there are also corner cases. (Behavior might be different in case of name clashes for dynamically created properties within a composition, changing behavior depending on the order of method invocations on a single object) My feeling is that traits should permit state and allow the renaming of member variables just as they allow the renaming of methods. Just to be clear, there is no such thing like renaming. Renaming is just not possible with a dynamic language like PHP. ($this-$bar = 'baz'; $this-$foo();... ) Best regards Stefan [1] http://www.iam.unibe.ch/~scg/Archive/Papers/Berg07eStatefulTraits.pdf -- Stefan Marr Programming Technology Lab Vrije Universiteit Brussel Pleinlaan 2 / B-1050 Brussels / Belgium http://prog.vub.ac.be/~smarr -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Grafts, Traits, horizontal reuse
On Fri, Apr 17, 2009 at 10:16 AM, Stefan Marr p...@stefan-marr.de wrote: For the sake of simplicity, we might discuss a very basic solution. It would be possible to introduce trait-local state only. Thus, all properties defined in a trait are only available within methods of the same trait, no other operations are able to access these properties. Yes, I think this is exactly right. Programmers who want to expose the state can do that by writing setters and getters. A trivial inconvenience compared to the pain of not being able to have multiple enhancements of the same third party class from multiple sources - something that comes up almost immediately when you start talking about plug-ins for frameworks. How ever, there are also corner cases. (Behavior might be different in case of name clashes for dynamically created properties within a composition, changing behavior depending on the order of method invocations on a single object) I'm not sure I grasp how these can happen in this scenario. Just to be clear, there is no such thing like renaming. Renaming is just not possible with a dynamic language like PHP. ($this-$bar = 'baz'; $this-$foo();... ) OK, but with strictly-trait-local state this is not an issue. A shame this can't be in 5.3 but we will get there. (: -- Tom Boutell P'unk Avenue 215 755 1330 punkave.com window.punkave.com -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Grafts, Traits, horizontal reuse
Hi Tom, On 17 Apr 2009, at 19:20, Tom Boutell wrote: How ever, there are also corner cases. (Behavior might be different in case of name clashes for dynamically created properties within a composition, changing behavior depending on the order of method invocations on a single object) I'm not sure I grasp how these can happen in this scenario. Well, it actually depends on the strictness of this idea. And its particular implementation. With the dynamic nature of PHP in mind, my first idea would be something like this, which is not ideal: class Base { // private $a; - intentionally left out because of //some smart approach to use meta-programming powers... public function setA($value) { $this-a = $value; } public function echoA() { echo $this-a; } } trait TraitUsingA { // var $a; - intentionally left out because of another smart approach for using // really clever meta-programming, not shown here public function setTraitA($value) { $this-a = $value; } public function echoTraitA() { echo $this-a; } } class MyClass { use TraitUsingA; } $a = new MyClass(); $a-setTraitA('trait'); $a-setA('base'); $a-echoTraitA(); // echos 'trait' $a-echoA(); // echos 'base' $b = new MyClass(); $b-setA('base'); $b-setTraitA('trait'); $b-echoTraitA(); // echos 'trait' $b-echoA(); // echos 'trait' The question here is how to handle property accesses, in particular accesses to unspecified properties. I actually would expect to have a lookup mechanism which first looks in the trait, and if the property is not found there, its going to the object. I expect this behavior, because it is similar to what we have with inheritance and properties defined by a superclass. If a property is not jet defined, I would expect it to be created in the most inner scope, like local variables. On the other hand, I also would expect, as in inheritance, properties to be found defined by super classes, or the class which defines the composition. But this only my intuitive solution, so this could of course be specified different. Best regards Stefan -- Stefan Marr Programming Technology Lab Vrije Universiteit Brussel Pleinlaan 2 / B-1050 Brussels / Belgium http://prog.vub.ac.be/~smarr -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Grafts, Traits, horizontal reuse
I've been catching up with the discussion of grafts and traits. Here at P'unk Avenue we do a lot of Symfony development, which frequently involves kludges to achieve horizontal reuse - ugly, clever, imaginative, combinations of the three but the first of the three is pretty much always present. PHP needs real horizontal reuse, no question. My first reaction to traits was positive - it's simple and simple is good. However I'm very concerned about the implications of not allowing state. In the real world people are going to want to do horizontal reuse that involves state. So they will work around it. It's true that if they are extending a class they have control over, they can do it fairly elegantly... In the parent class: public $traitData = null; public function __construct() { $traitData = array(); } Now, in a trait method, they can do: public function mymethod() { $this-traitData['age'] = 38; } The PHP 5.3 cycle breaker can presumably clean up any references made in traitData when all noncyclical references to the object itself are gone. However this is not without problems. There will be collisions between key names in traitData when mixing traits, and there will be no way to detect those conflicts and automatically resolve them. It's presumably less efficient than an implementation of state in the core. And most importantly, it only works if the parent class can be modified by the programmer trying to extend it. One of the stated goals of horizontal reuse is to accommodate adding multiple non-mutually-exclusive extensions, written by you and not written by you, to parent classes you didn't write (of course, without the written by you and not written by you... multiple non-mutually-exclusive part, you could just use a subclass). So what happens when the programmer wants to write a trait to extend classes they didn't write, and they need to save state? Well, their first workaround attempt might be this: $foo-bar = I'm an object!; $hash[$foo]['age'] = 5; echo($hash[$foo]['age']); That is, use the object as a key in a hash. Fortunately, PHP doesn't allow objects as keys in hashes. That's good, because this otherwise clever technique would leave stray references in the hash which would never get cleaned up, ever. Cycle breaking or no cycle breaking. We're right back in why can't I manipulate a lot of objects in a 'for' loop without hating life land. Okay, so what's our hypothetical user's next workaround going to be? In some cases, they're just stuck. In others, the parent class does offer some sort of unique identifier. Common examples being Propel and Doctrine objects, which have getId() methods. So the programmer does this (simplest possible implementation to show the idea): public function myTraitMethod() { global $hash; // * $hash[$this-getId()]['age'] = 38; } This works. But it leaks memory forever. When the object goes away, there is no way to break the connection to the data in $hash. Which might not be as trivial as 'age'. More likely it'll be crammed with objects with references to objects with... you get the idea. To clean these references up you'd need a destructor. Except the traits RFC makes no mention of destructors. So you'd need a parent class destructor that explicitly invoked trait destructors. Except you went this road in the first place because you didn't have control over the parent class to make changes like that. Etc. Since PHP is moving in the direction of better garbage collection (and thank heaven for that), it's a bad idea to make a design decision that will lead developers in the direction of breaking that garbage collection system. The natural thought at this point is to endorse grafts. But the grafts proposal has more complex implementation requirements and there doesn't seen to be an existing patch to implement it. The big stumbling point is that in a naive implementation, $this would refer to the graft object, not its parent. But the programmer expects to be able to pass $this around to other code which will expect the parent object, etc. My feeling is that traits should permit state and allow the renaming of member variables just as they allow the renaming of methods. If that's an implementation problem, it might be better to transparently move the trait member variables to a hash and interpret references to those variable names accordingly within the trait methods. The member variable hash becomes $this-__traitName_0, $this-__traitName_1, etc. for each consecutive use of the same trait in the same class (if we really need that feature). (*) Yes, $hash shouldn't be a global, it should be a static member of a globalDataManager class or something. Makes no difference for purposes of this discussion. -- Tom Boutell P'unk Avenue 215 755 1330 punkave.com window.punkave.com -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Grafts, Traits, horizontal reuse
On Nov 24, 2008, at 9:27 PM, Christopher Vogt wrote: Interfaces are helpful in combination with type hinting, but for people who prefer duck typing, it is reasonable to not explicitly define them. It sounds like you are saying that if you prefer duck typing then interfaces have no use. If this is what you mean, I disagree strongly. Interfaces are primarily to create a set of methods that define an interface. Then the compiler can enforce implementation of that interface in any class that claims to implement the interface. This is the core utility of interfaces. Alan -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Grafts, Traits, horizontal reuse
Hello Christopher, Tuesday, November 25, 2008, 3:27:45 AM, you wrote: Hej Marcus, I like your approach. It is clear and simple. It would probably solve 90% of the cases, where delegation is needed. I want to add that a manually defined method should automatically overwrite a delegated method of the same name. But I also want to bring up two reasonable situations your approach does not cover. Your approach does not allow to delegate only a selection of methods. This makes sense in order to limit the delegation to known functionality. To stick to your example, without selective delegation, new methods added to Counter would be automatically delegated to CounterUser. This might break things. A second situation not covered by your approach is renaming of delegated methods. This can be desirable due to name clashes or name changes for better understandability. Of course there is always the fall back to manually implementing delegation. And your approach alone would already be quite useful syntactic sugar. But additional syntactic sugar for the two situations described above would still be nice :). Another thing. I am not sure if you intended that, but I think delegation should not force using an Interface definition. Interfaces are helpful in combination with type hinting, but for people who prefer duck typing, it is reasonable to not explicitly define them. Let's leave this choice to the people :). Your points are all well observed. And yes I limit what my approach can do in order to Keep It Simple Safe (KISS). While still being able to manually interfere with/overload the autogenerated code when necessary. At the same time forcing to delegate to a defined Interface and not allowing to rename on the fly prevents abusing the functionality and helps maintainability. On the other hand it forces you to think before coding as this approach comes with a lack of functionality. Maybe in a second step we could make the defined interface optional but with my implementation in mind that might not be the easiest thing to do. Best regards Christopher Best regards, Marcus -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Grafts, Traits, horizontal reuse
Hi, On 25 Nov 2008, at 13:39, Marcus Boerger wrote: Your points are all well observed. And yes I limit what my approach can do in order to Keep It Simple Safe (KISS). While still being able to manually interfere with/overload the autogenerated code when necessary. At the same time forcing to delegate to a defined Interface and not allowing to rename on the fly prevents abusing the functionality and helps maintainability. On the other hand it forces you to think before coding as this approach comes with a lack of functionality. Ok, but now we start to talk about two clearly different things. On the one hand something like traits, mixins, or what ever, and restricted syntax sugar for delegation on the other hand. While designing grafts, the idea was to provide a similar power like traits do, but introducing state and encapsulation. From my point of view, there is no other way to achieve this. At least I have not found it. All things in between, like unbreakable traits add more complexity then they solve problems. So actually, we are somewhere near the point which I intended to reach with my proposal. The questions we should answer now are: - Does PHP need horizontal reuse? - Do we go for an explicit solution? (traits) - Do we go for some sort of syntax sugar for delegation? (grafts, delegate keyword) - Or do we go the implicit way? (mixins, phyton multiple-inheritance) Nevertheless, I would love to get some more comments on grafts before answering this questions, because this could give additional insights in the real problems with this approach and some ideas for improvements. Best Regards Stefan -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Grafts, Traits, horizontal reuse
Hi Christopher, thanks for (re-)starting the discussion how to make horizontal reuse easier in PHP. Am Donnerstag, den 13.11.2008, 16:59 +0100 schrieb Christopher Vogt: [...] I had a chat with Stefan about his Traits/Grafts RFC and he suggested we should rather continue a discussion here. I really liked to see the Grafts proposal. In traits and regular inheritance the implementation code of several entities is somehow mixed and as a result one entities code can break another entities code. To keep things fair, there were proposals to keep traits completely stateless and to allow abstract methods in traits, so that traits can sort of request the implementation of a certain method. This would keep the inheritance chain pretty stable. The great thing about Grafts is that the implementation is not mixed. Grafts are completely encapsulated entities with their own state. I think in many cases where inheritance or traits seem tempting, complete encapsulation is actually the cleaner solution. I see the point of having encapsulated state, I still wonder if it would be better for us to have something simpler. Simpler, as in avoiding state at all. So if we had traits without state at all a) the concept is easy to explain (like interfaces define the API, classes keep state, traits encapsulate implementation). A nice and easy explainable hierarchy of responsibilities. [... Details about grafts ...] However a problem remains. The methods of counter return $this (aka implement a fluent interface). One idea that came to my mind to solve this problem: PHP could provide a keyword fluent that replaces a methods return value to form a fluent interface i.e. return $this: class QueueTicketPrinter{ use Counter as private $counter{ public fluent current(); public fluent reset(); } public function takeNumber(){ print 'your number is .$this-counter-current(); $this-counter-inc(); } } The keyword fluent ignores whatever value the Counter function may return and returns an the instance of QueueTicketPrinter instead. That's a good example why I have the feeling they are a hack. I mean a fluent keyword just for a single use case. Another thing, how could I return the class name of the current class? public class current(). And so on. At the end it is an issue of late graft binding (similar to late static binding). Finally, can somebody provide a sensible use case for traits, that cannot be solved with Grafts? I am sure there is, but I am currently lacking one. I can't think of any (except from late graft binding), however not having anything against does not mean it is a good idea :) I still prefer traits as they are easier to explain from my point of view, the concept is more clear and that's the spirit that fits pretty well for PHP. cu, Lars signature.asc Description: Dies ist ein digital signierter Nachrichtenteil
Re: [PHP-DEV] Grafts, Traits, horizontal reuse
Hello Stefan, Sunday, November 16, 2008, 4:36:18 PM, you wrote: Hi, Christopher Vogt schrieb: Hej everybody, I really liked to see the Grafts proposal. Well, I'm still in love with the more powerful (because they are interweaveable(breakable)) Traits ;) The Grafts proposal, however, suffered a little from being born out of traits, I think. Something similar to Grafts is already possible in current php, but it is not very beautiful. If we start from there however, Grafts could become very helpful syntactic sugar. Actually I think this could be a problem for the conciseness of the language. Introducing syntactic sugar for special situations has to be done carefully. Nevertheless, from my perspective forwarding (aka delegation) is a very common concept in OOP which would be worth to be supported by a special syntax. class QueueTicketPrinter{ use Counter as private $counter{ public current(); public reset(); } public function takeNumber(){ print 'your number is .$this-counter-current(); $this-counter-inc(); } } I like this idea, but there are still some problems to be solved. The major problem with grafts is still the initialization of objects. What to do with constructors which require parameter? An other issue I see is the question of introducing to much additional syntax. It could be reduced to something like: private $counter : Counter [use] { //with or without use? public current(); public reset(); } But now anonymous grafts aren't possible anymore and actually, Grafts had been design without an identity own their own. On the other hand, this notation could introduce the possibility for advanced initialization: class QueueTicketPrinter{ private $cntInitValue; public function __construct($cntValue) { $this-cntInitValue = $cntValue; } private $counter : Counter(cntInitValue) { public current(); public reset(); } public function takeNumber(){ print 'your number is .$this-counter-current(); $this-counter-inc(); } } This is hardly more than delegates. Actually the only thing more you get is hiding stuff which is incompatible to the thing you loose at the same time. That is your grafts do not support interface delegation. So My preference is being able to actually do that (and mixins/traits do). Example: Interface Counter { function current(); function reset(); } Class CounterImpl implements Counter { private $cnt = 0; function current() { return $this-cnt; } function reset() { $this-cnt = 0; } } Class CounterUser implements Counter { delegate Counter $counter; function __construct() { $this-counter = new CounterImpl; } } The keyword delegate makes sure $counter is a member that must implement Counter. Assigning any other value would result in an exception or other error. To make it easier the delegate declaration wcould contain the initialization already and turn the delegate member into a read only member. deletegate Counter $counter = new CounterImpl; Finally, can somebody provide a sensible use case for traits, that cannot be solved with Grafts? I am sure there is, but I am currently lacking one. Every time you just like to compose a class from different kinds of behaviors Traits are superior. The use cases discussed in literature are class hierarchies for collection classes and streams. For both hierarchies, the interweaving of methods from different traits is a helpful property to build all variations of semantics. Kind Regards Stefan marcus Best regards, Marcus -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Grafts, Traits, horizontal reuse
Hej Marcus, I like your approach. It is clear and simple. It would probably solve 90% of the cases, where delegation is needed. I want to add that a manually defined method should automatically overwrite a delegated method of the same name. But I also want to bring up two reasonable situations your approach does not cover. Your approach does not allow to delegate only a selection of methods. This makes sense in order to limit the delegation to known functionality. To stick to your example, without selective delegation, new methods added to Counter would be automatically delegated to CounterUser. This might break things. A second situation not covered by your approach is renaming of delegated methods. This can be desirable due to name clashes or name changes for better understandability. Of course there is always the fall back to manually implementing delegation. And your approach alone would already be quite useful syntactic sugar. But additional syntactic sugar for the two situations described above would still be nice :). Another thing. I am not sure if you intended that, but I think delegation should not force using an Interface definition. Interfaces are helpful in combination with type hinting, but for people who prefer duck typing, it is reasonable to not explicitly define them. Let's leave this choice to the people :). Best regards Christopher -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Grafts, Traits, horizontal reuse
Hi, Christopher Vogt schrieb: Hej everybody, I really liked to see the Grafts proposal. Well, I'm still in love with the more powerful (because they are interweaveable(breakable)) Traits ;) The Grafts proposal, however, suffered a little from being born out of traits, I think. Something similar to Grafts is already possible in current php, but it is not very beautiful. If we start from there however, Grafts could become very helpful syntactic sugar. Actually I think this could be a problem for the conciseness of the language. Introducing syntactic sugar for special situations has to be done carefully. Nevertheless, from my perspective forwarding (aka delegation) is a very common concept in OOP which would be worth to be supported by a special syntax. class QueueTicketPrinter{ use Counter as private $counter{ public current(); public reset(); } public function takeNumber(){ print 'your number is .$this-counter-current(); $this-counter-inc(); } } I like this idea, but there are still some problems to be solved. The major problem with grafts is still the initialization of objects. What to do with constructors which require parameter? An other issue I see is the question of introducing to much additional syntax. It could be reduced to something like: private $counter : Counter [use] { //with or without use? public current(); public reset(); } But now anonymous grafts aren't possible anymore and actually, Grafts had been design without an identity own their own. On the other hand, this notation could introduce the possibility for advanced initialization: class QueueTicketPrinter{ private $cntInitValue; public function __construct($cntValue) { $this-cntInitValue = $cntValue; } private $counter : Counter(cntInitValue) { public current(); public reset(); } public function takeNumber(){ print 'your number is .$this-counter-current(); $this-counter-inc(); } } Finally, can somebody provide a sensible use case for traits, that cannot be solved with Grafts? I am sure there is, but I am currently lacking one. Every time you just like to compose a class from different kinds of behaviors Traits are superior. The use cases discussed in literature are class hierarchies for collection classes and streams. For both hierarchies, the interweaving of methods from different traits is a helpful property to build all variations of semantics. Kind Regards Stefan -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Grafts, Traits, horizontal reuse
Hej, I really liked to see the Grafts proposal. Well, I'm still in love with the more powerful (because they are interweaveable(breakable)) Traits ;) I don't think there has to be a choice between Grafts and Traits. They serve different purposes and I don't see a reason they shouldn't co-exit. Traits implement code reuse. Code is merged. This is very powerful but can break code. Grafts implement delegation. This is less powerful, but can't break, which makes it preferable, whenever possible. Actually I think this could be a problem for the conciseness of the language. Introducing syntactic sugar for special situations has to be done carefully. In my eyes (well-chosen) syntactic sugar contributes a lot to language conciseness. And every language decision should be done carefully, right? from my perspective forwarding (aka delegation) is a very common concept in OOP which would be worth to be supported by a special syntax. I strongly think so. I like this idea, but there are still some problems to be solved. The major problem with grafts is still the initialization of objects. What to do with constructors which require parameter? Good point. My new suggestion at the end covers it. An other issue I see is the question of introducing to much additional syntax. It could be reduced to something like: private $counter : Counter [use] { //with or without use? public current(); public reset(); } I don't see the above having less syntax than my suggestion. as or : is both syntax. I doubt, I would rather stick to a keyword already in the language in similar semantics. For Comparison, my suggestion was: use Counter as private $counter{ public current(); public reset(); } But now anonymous grafts aren't possible anymore and actually, Grafts had been design without an identity own their own. Yes and I don't think anonymous Grafts would be a good idea. They would make access to grafts complicated and significantly limited including valid use cases. Being explicit instead of implicit helps here in my eyes. On the other hand, this notation could introduce the possibility for advanced initialization: private $cntInitValue; public function __construct($cntValue) { $this-cntInitValue = $cntValue; } private $counter : Counter(cntInitValue) { public current(); public reset(); } I don't think that's a good idea. I admit it's very close to my suggestion, but now it reached a point, where it does something very familiar, namely creating an new object, using a very unfamiliar way and also new syntax. So I make a new suggestion that puts everything much closer to present PHP: class QueueTicketPrinter{ private $counter { public current(); public restart() from reset(); }; public function __construct($cntValue) { $this-counter = new Counter( $cntValue ); } public function takeNumber(){ print 'your number is .$this-current(); $this-counter-inc(); } } And two syntax variants: Variant 1: private $counter use { public current(); reset() as public restart(); }; Variant 2: private $counter delegate { public current(); public restart() to reset(); }; This suggestion requires a new runtime Error/Exception for cases when a method of QueueTicketPrinter is called that is delegated to a method that $counter does not implement. Every time you just like to compose a class from different kinds of behaviors Traits are superior. More powerful yes, superior no. Delegation and inheritance (counting traits as a variant of inheritance) both allow functionality re-use but both also resemble a trade-off between flexibility and breakability. Inheritance is more flexible, but can easily break, especially when inheritance structures grow. Delegation is less flexible, but can't break (from reuse), even in large structures. So both are justified. Best regards Christopher P.S. I should mention that I do not have any insight of the actual implementation of PHP. So if I suggest something insensibly hard to implement, just shout :). -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
[PHP-DEV] Grafts, Traits, horizontal reuse
Hej everybody, I had a chat with Stefan about his Traits/Grafts RFC and he suggested we should rather continue a discussion here. I really liked to see the Grafts proposal. In traits and regular inheritance the implementation code of several entities is somehow mixed and as a result one entities code can break another entities code. The great thing about Grafts is that the implementation is not mixed. Grafts are completely encapsulated entities with their own state. I think in many cases where inheritance or traits seem tempting, complete encapsulation is actually the cleaner solution. The Grafts proposal, however, suffered a little from being born out of traits, I think. Something similar to Grafts is already possible in current php, but it is not very beautiful. If we start from there however, Grafts could become very helpful syntactic sugar. Let's look at current PHP first: class Counter { private $cnt = 0; public function inc() { $this-cnt++; return $this; } public function reset() { $this-cnt = -1; $this-inc(); return $this; } public function current(){ return $this-cnt; return $this; } } class QueueTicketPrinter{ private $counter; public __construct(){ $this-counter = new Counter(); } public function takeNumber(){ print 'your number is .$this-counter-current(); $this-counter-inc(); } public function current(){ $this-counter-current(); } public function reset(){ $this-counter-reset(); } } This is a lot of code in QueueTicketPrinter for that it mostly reuses Counter. Grafts as syntactic sugar could make it look as short as: class QueueTicketPrinter{ use Counter as private $counter{ public current(); public reset(); } public function takeNumber(){ print 'your number is .$this-counter-current(); $this-counter-inc(); } } However a problem remains. The methods of counter return $this (aka implement a fluent interface). One idea that came to my mind to solve this problem: PHP could provide a keyword fluent that replaces a methods return value to form a fluent interface i.e. return $this: class QueueTicketPrinter{ use Counter as private $counter{ public fluent current(); public fluent reset(); } public function takeNumber(){ print 'your number is .$this-counter-current(); $this-counter-inc(); } } The keyword fluent ignores whatever value the Counter function may return and returns an the instance of QueueTicketPrinter instead. Finally, can somebody provide a sensible use case for traits, that cannot be solved with Grafts? I am sure there is, but I am currently lacking one. Cheers Christopher P.S. Hope that stupid post before does not make me seem too much like it ;). -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php