FAQ
Hi:

Traits do not provide any special provisioning for handling properties, especially, there is no language solution for handling colliding property names.
The current solution/idiom for handling state safely in a trait is to use either abstract set/get methods or an abstract get that returns a reference to the property in the class.

However, at the moment it is possible to define properties in a trait:

trait Foo {
private $a;
public $foo;
}

For the moment, that information is completely ignored, thus:

class Bar {
use Foo;
}
property_exists('Bar', 'a') === false


Well, and that is a rather inconsistent status-quo.

I would like to have that fixed in one or another way.

One possibility would be to forbid property definition in a trait altogether.
That reduces a bit the possibility to have wrong expectations about properties, however, the dynamic property creation is still possible.

Another way would be to merge the properties in the composing class.
The question here would be how to treat visibility modifiers: how to merge public and private, should it result in public, or private?
And, to discorage users to go this way, should there be a STRICT notice? Options here are a notice whenever a property is defined in a trait, or whenever properties are silently merged.


Comments very welcome.

Thanks
Stefan

--
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

Search Discussions

  • Nathan Nobbe at Dec 11, 2010 at 6:35 pm

    On Sat, Dec 11, 2010 at 9:47 AM, Stefan Marr wrote:

    Hi:

    Traits do not provide any special provisioning for handling properties,
    especially, there is no language solution for handling colliding property
    names.
    The current solution/idiom for handling state safely in a trait is to use
    either abstract set/get methods or an abstract get that returns a reference
    to the property in the class.

    However, at the moment it is possible to define properties in a trait:

    trait Foo {
    private $a;
    public $foo;
    }

    For the moment, that information is completely ignored, thus:

    class Bar {
    use Foo;
    }
    property_exists('Bar', 'a') === false


    Well, and that is a rather inconsistent status-quo.

    I would like to have that fixed in one or another way.

    One possibility would be to forbid property definition in a trait
    altogether.
    That reduces a bit the possibility to have wrong expectations about
    properties, however, the dynamic property creation is still possible.

    Another way would be to merge the properties in the composing class.
    The question here would be how to treat visibility modifiers: how to merge
    public and private, should it result in public, or private?
    And, to discorage users to go this way, should there be a STRICT notice?
    Options here are a notice whenever a property is defined in a trait, or
    whenever properties are silently merged.
    I would prefer they be definable within traits and merged into classes,
    otherwise traits will not have the chance to be self-contained entities of
    reusable logic. Also, I think merging them in is consistent with the
    treatment given to methods as they pertain to traits.

    As I'm sure you know:
    <?php
    class A {
    use SomeTrait;
    }

    trait SomeTrait {
    public function traitMethod() {}
    }

    method_exists('A', 'traitMethod') === true;
    ?>

    Regarding visibility modifiers, why not carry them over from the trait
    directly, private in the trait definition results in private in the class
    definition. Lastly, I'm not sure why you would want to discourage this
    usage, I would plan on adding properties in traits myself.

    -nathan
  • Stefan Marr at Dec 12, 2010 at 10:59 am
    Hi Nathan:
    On 11 Dec 2010, at 19:35, Nathan Nobbe wrote:

    Regarding visibility modifiers, why not carry them over from the trait directly, private in the trait definition results in private in the class definition.
    The problem will be hopefully more clear in the following example:

    trait StateMachineDoor {
    private $currentState;
    public function open() {....}
    }

    trait StateMachineElevator {
    public $currentState;
    public function callElevator() { ... }
    }

    These two traits are not compatible since currentState has different semantics in both traits.
    With the current design of traits, there is no language solution to this problem.

    The suggestions to avoid the problem are to use better names like $currentDoorState and $currentElevatorState, or to rely on accessors which is currently the only variant in which the programmer will notice that there is an incompatibility:

    trait StateMachineDoor {
    abstract function &getCurrentState();
    public function open() {....}
    }

    trait StateMachineElevator {
    abstract function &getCurrentState();
    public function callElevator() { ... }
    }

    However, you might have a different situation, one where the traits are composable with respect to their state, i.e., they need to work on the same state:

    trait OutputIterator {
    public $array; // not sure why that is public here, but the implementor chose to make it public...
    public function printNext() {...}
    }

    trait SortArray {
    private $array; // this developer chose to make the array private, for what ever reason...
    public function doSort() { ... }
    }

    I hope that makes the possible situations clear: state can either be composable or not, that really depends
    on the trait. And there is no language solution for it build in at the moment.

    So, back to my original question:

    class SomethingOutputableAndSortable {
    use OutoutIterator, SortArray;
    }

    What is the visibility of $array supposed to be in this class? private or public?

    And further, in the very first example of this mail, ideally there should be some warning, however, that warning would be annoying for the last example, since here the state does not collide...

    Best regards
    Stefan

    PS: there has been discussion on stateful traits before, but the language solutions to that where considered to complex.

    --
    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
  • Sebastian Bergmann at Dec 11, 2010 at 6:36 pm

    On 12/11/2010 05:47 PM, Stefan Marr wrote:
    Another way would be to merge the properties in the composing class. +1
    The question here would be how to treat visibility modifiers
    One option would be to only allow private. That way only methods from
    the trait would have access and collisions could be prevented.
    And, to discorage users to go this way, should there be a STRICT
    notice?
    If you want to discourage attribute declaration in a trait, don't
    allow it at all.

    --
    Sebastian Bergmann Co-Founder and Principal Consultant
    http://sebastian-bergmann.de/ http://thePHP.cc/
  • Stefan Marr at Dec 12, 2010 at 12:24 am
    Hi Sebastian:
    On 11 Dec 2010, at 19:36, Sebastian Bergmann wrote:
    And, to discorage users to go this way, should there be a STRICT
    notice?
    If you want to discourage attribute declaration in a trait, don't
    allow it at all.
    Not allowing it is not an option as far as I can tell.

    You can always use dynamically defined properties in a method.
    Changing that would change the whole character of PHP.
    Then we would have two types of methods, methods that are defined in the class directly and can do what ever they want with properties, and methods from traits which are restricted and can't access any state.

    I think, that would be to much penalty for all the valid use cases where a naive property usage in a trait is still just fine.

    Best regards
    Stefan

    --
    Sebastian Bergmann Co-Founder and Principal Consultant
    http://sebastian-bergmann.de/ http://thePHP.cc/

    --
    PHP Internals - PHP Runtime Development Mailing List
    To unsubscribe, visit: http://www.php.net/unsub.php
    --
    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
  • Sebastian Bergmann at Dec 12, 2010 at 9:02 am

    On 12/12/2010 01:24 AM, Stefan Marr wrote:
    If you want to discourage attribute declaration in a trait, don't
    allow it at all.
    Not allowing it is not an option as far as I can tell.
    Good! :-)

    --
    Sebastian Bergmann Co-Founder and Principal Consultant
    http://sebastian-bergmann.de/ http://thePHP.cc/
  • Pierre Joye at Dec 11, 2010 at 10:13 pm
    hi,

    Would it be possible to somehow document what you are discussing here?
    It is not too easy to keep track of all discussions about traits
    (along other things). Maybe in draft RFC or a simple page in the wiki.
    Doing so will help to have a quick view about the open questions or
    recent changes/propositions.

    Thanks!
    On Sat, Dec 11, 2010 at 5:47 PM, Stefan Marr wrote:
    Hi:

    Traits do not provide any special provisioning for handling properties, especially, there is no language solution for handling colliding property names.
    The current solution/idiom for handling state safely in a trait is to use either abstract set/get methods or an abstract get that returns a reference to the property in the class.

    However, at the moment it is possible to define properties in a trait:

    trait Foo {
    private $a;
    public  $foo;
    }

    For the moment, that information is completely ignored, thus:

    class Bar {
    use Foo;
    }
    property_exists('Bar', 'a') === false


    Well, and that is a rather inconsistent status-quo.

    I would like to have that fixed in one or another way.

    One possibility would be to forbid property definition in a trait altogether.
    That reduces a bit the possibility to have wrong expectations about properties, however, the dynamic property creation is still possible.

    Another way would be to merge the properties in the composing class.
    The question here would be how to treat visibility modifiers: how to merge public and private, should it result in public, or private?
    And, to discorage users to go this way, should there be a STRICT notice? Options here are a notice whenever a property is defined in a trait, or whenever properties are silently merged.


    Comments very welcome.

    Thanks
    Stefan

    --
    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


    --
    PHP Internals - PHP Runtime Development Mailing List
    To unsubscribe, visit: http://www.php.net/unsub.php


    --
    Pierre

    @pierrejoye | http://blog.thepimp.net | http://www.libgd.org
  • Stefan Marr at Dec 11, 2010 at 11:32 pm
    Hi Pierre:
    On 11 Dec 2010, at 23:13, Pierre Joye wrote:

    hi,

    Would it be possible to somehow document what you are discussing here?
    It is not too easy to keep track of all discussions about traits
    (along other things). Maybe in draft RFC or a simple page in the wiki.
    Doing so will help to have a quick view about the open questions or
    recent changes/propositions.
    Yes, I try to keep track of all this in the RFC:
    http://wiki.php.net/rfc/horizontalreuse?do=revisions

    The current status of the property behavior is not yet documented explicitly, it is only implied since it is not handled at all...
    And, it is the only open question that 'needs' to be solved since it is an inconsistency.
    For instance the 'require Interface' is more like an additional feature.

    Best regards
    Stefan

    Thanks!
    On Sat, Dec 11, 2010 at 5:47 PM, Stefan Marr wrote:
    Hi:

    Traits do not provide any special provisioning for handling properties, especially, there is no language solution for handling colliding property names.
    The current solution/idiom for handling state safely in a trait is to use either abstract set/get methods or an abstract get that returns a reference to the property in the class.

    However, at the moment it is possible to define properties in a trait:

    trait Foo {
    private $a;
    public $foo;
    }

    For the moment, that information is completely ignored, thus:

    class Bar {
    use Foo;
    }
    property_exists('Bar', 'a') === false


    Well, and that is a rather inconsistent status-quo.

    I would like to have that fixed in one or another way.

    One possibility would be to forbid property definition in a trait altogether.
    That reduces a bit the possibility to have wrong expectations about properties, however, the dynamic property creation is still possible.

    Another way would be to merge the properties in the composing class.
    The question here would be how to treat visibility modifiers: how to merge public and private, should it result in public, or private?
    And, to discorage users to go this way, should there be a STRICT notice? Options here are a notice whenever a property is defined in a trait, or whenever properties are silently merged.


    Comments very welcome.

    Thanks
    Stefan

    --
    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


    --
    PHP Internals - PHP Runtime Development Mailing List
    To unsubscribe, visit: http://www.php.net/unsub.php


    --
    Pierre

    @pierrejoye | http://blog.thepimp.net | http://www.libgd.org
    --
    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
  • Richard Quadling at Dec 13, 2010 at 1:32 pm

    On 11 December 2010 23:31, Stefan Marr wrote:
    The current status of the property behavior is not yet documented explicitly
    On the assumption that traits WILL include properties (with
    visibility) and aliasing can do all its magic, how would the situation
    be handled where multiple traits define shared properties.

    I've not got a use case, but say trait1 and trait2 both define the
    same property.

    Assuming name conflicts are handled via aliasing, then the property
    needs to alert the aliasing code that this property is a non
    conflicting property. All traits wanting to access the shared property
    would have to reveal their intentions.

    I can think of 2 ways to handle this (but I'm no genius here, so take
    them apart at your pleasure).

    1 - The trait's code marks shared properties with a keyword (shared,
    common, virtual, something). During incorporation of the trait into
    the main class, any marked properties are checked for visibility only.
    2 - The trait's code uses a &$property. The fact that this is a
    reference would require the creation of the property (if it doesn't
    already exist) whilst the trait is being compiled into the main class.
    I'd guess this would be the least difficult to implement, but I know
    squat about this.

    I'm guessing the order of handling the traits would be significant here.

    Trait1 uses $property, Trait2 uses $property - conflict. Must be
    resolved by aliasing or an error.
    Trait1 uses &$property, Trait2 uses &$property - all ok. Trait1 wants
    access a non existing property, so one is created. Trait2 is sharing
    the now pre-existing property.
    Trait1 uses &$property, Trait2 uses $property - conflict. Trait1 wants
    access a non existing property, so one is created. Trait2's $property
    must be aliased to an error.
    Trait1 uses $property, Trait2 uses &$property - all ok. Trait1's
    $property is added as expected. Trait2 is sharing the now pre-existing
    property.

    Richard.


    --
    Richard Quadling
    Twitter : EE : Zend
    @RQuadling : e-e.com/M_248814.html : bit.ly/9O8vFY
  • Stefan Marr at Dec 13, 2010 at 4:16 pm
    Hi Richard:
    On 13 Dec 2010, at 14:31, Richard Quadling wrote:
    On 11 December 2010 23:31, Stefan Marr wrote:
    The current status of the property behavior is not yet documented explicitly
    On the assumption that traits WILL include properties (with
    visibility) and aliasing can do all its magic, how would the situation
    be handled where multiple traits define shared properties.

    I've not got a use case, but say trait1 and trait2 both define the
    same property.

    Assuming name conflicts are handled via aliasing, then the property
    needs to alert the aliasing code that this property is a non
    conflicting property.
    Just to emphasize this another time: aliasing is no magic, it is NOT renaming.
    (And it is only supported for methods.)

    The important implication here is, that aliasing is only useful from the viewpoint of the composing class.
    Form the trait's perspective, aliasing does not have any effect.

    Aliasing can be used to make a function accessible that has a naming conflict with another function.
    It enables composition of traits, but does not do anything with regard which function names a trait-function calls. In PHP all function names are late bound, there is no inner binding between functions in traits.

    Hope that clarifies what I perceived as a misconception.



    Best regards
    Stefan

    --
    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
  • Richard Quadling at Dec 13, 2010 at 1:13 pm

    On 11 December 2010 16:47, Stefan Marr wrote:
    Hi:

    Traits do not provide any special provisioning for handling properties, especially, there is no language solution for handling colliding property names.
    The current solution/idiom for handling state safely in a trait is to use either abstract set/get methods or an abstract get that returns a reference to the property in the class.

    However, at the moment it is possible to define properties in a trait:

    trait Foo {
    private $a;
    public  $foo;
    }

    For the moment, that information is completely ignored, thus:

    class Bar {
    use Foo;
    }
    property_exists('Bar', 'a') === false


    Well, and that is a rather inconsistent status-quo.

    I would like to have that fixed in one or another way.

    One possibility would be to forbid property definition in a trait altogether.
    That reduces a bit the possibility to have wrong expectations about properties, however, the dynamic property creation is still possible.

    Another way would be to merge the properties in the composing class.
    The question here would be how to treat visibility modifiers: how to merge public and private, should it result in public, or private?
    And, to discorage users to go this way, should there be a STRICT notice? Options here are a notice whenever a property is defined in a trait, or whenever properties are silently merged.


    Comments very welcome.

    Thanks
    Stefan
    From the rfc [1], "A Trait is similar to a class, but only intended to
    group functionality".

    I'm guessing that says it all. A trait has no properties.

    But.

    If properties are to be added to a trait, I think that should come as
    a further enhancement and let traits start out as "methods only".

    If a trait is properties, then also supporting constants and the other
    sort of set/get properties would provide a strong level of
    consistency. If I can put it in a class, I can put it in a trait.

    As visibility on the traits methods can be manipulated via the
    aliasing mechanism, so should any visibility to a property.

    Richard.

    [1] http://wiki.php.net/rfc/horizontalreuse
    --
    Richard Quadling
    Twitter : EE : Zend
    @RQuadling : e-e.com/M_248814.html : bit.ly/9O8vFY
  • Stefan Marr at Dec 13, 2010 at 4:02 pm
    Hi Richard:
    On 13 Dec 2010, at 14:13, Richard Quadling wrote:

    From the rfc [1], "A Trait is similar to a class, but only intended to
    group functionality".

    I'm guessing that says it all. A trait has no properties.
    It is really a practical concern of language consistency for the moment.
    I am not talking about any fancy new language feature to handle state.

    At the moment, I am just concerned with examples like the following:

    trait Foo {
    function bar() {
    $this->baz = 'abcd';
    }
    }

    If that example becomes more complex, I would consider it to be good software engineering practice to document the usage of $this->baz and its semantic.

    For classes this is usually done by explicitly naming the property in the class body.

    At the moment, there is nothing which hinders you in doing that for a trait.

    However, since traits do not provide any safety provisioning for state, i.e., there is no collision handling for properties, the question is, how do we either promote to use explicit accessors or how do we deal with the inevitable and certainly justified use of properties in one or the other way.

    Best regards
    Stefan

    --
    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
  • Larry Garfield at Dec 14, 2010 at 2:27 am

    On Monday, December 13, 2010 10:02:13 am Stefan Marr wrote:

    However, since traits do not provide any safety provisioning for state,
    i.e., there is no collision handling for properties, the question is, how
    do we either promote to use explicit accessors or how do we deal with the
    inevitable and certainly justified use of properties in one or the other
    way.

    Best regards
    Stefan
    Thinking about it, I'm not sure that accessors are really a solid solution
    either.

    Behavior has to have something to behave on. So whether you have

    $this->foo

    or

    $foo = $this->getFoo();
    // Do stuff with $foo
    $this->setFoo($foo);

    You still have a dependency that the composing class have either a property
    named $foo or a pair of (frankly pointless) get/set methods.

    So either a composing class needs to know about the internal implementation
    details of a trait (what it calls variables inside of a method) so that it can
    provide what the trait needs, or a trait needs to be able to carry around its
    own implementation details.

    So it seems to me like we can't not let traits carry properties, which means
    we need to resolve them some how.

    --Larry Garfield
  • Stefan Marr at Dec 18, 2010 at 3:29 pm
    Hi Larry:
    On 16 Dec 2010, at 23:31, Larry Garfield wrote:

    I am fine with this approach, with 2 caveats:

    - If you actually do want to make two traits use the same property, it looks like the answer here is "Either have no property and demand the existence of an accessor that returns by reference, or you can't write E_NOTICE-safe code". Is that true?
    Yes, that is the tradeoff, perhaps the notice could be restricted be shown in strict-mode only.

    The manual says the following about E_STRICT, so it seems to fit, but I am not sure about the usual usage of E_STRICT throughout the engine.

    Manual:
    Note:
    In PHP 5 a new error level E_STRICT is available. As E_STRICT is not included within E_ALL you have to explicitly enable this kind of error level. Enabling E_STRICT during development has some benefits. STRICT messages will help you to use the latest and greatest suggested method of coding, for example warn you about using deprecated functions.
    - When the visibility collides, should we be folding to the most restrictive or least restrictive? I'm not sure myself; I'm more interested in your reasoning for going for most-restrictive.
    So, in general, I think, there is no 'right thing' to do here, because the definitions seem to be incompatible but that is only decidable at the application-level.

    There is another, related, edge-case in the test case below.
    In the test we have different initial values for the properties, which makes it 'obvious' that they are incompatible.
    Thus, in that case I would argue for a E_COMPILE_ERROR instead of a notice.

    The reason to use the stricter modifier is, well, arbitrary.

    At least I do not find an argument for either way that completely convinces me.
    At the moment, the main reason is that 'public' can be considered to be the default visibility modifier.
    Based on the semantics of 'var' and dynamic properties.
    Thus, private tends to imply that an additional constraint was consciously applied to the property, which should be preserved.
    Well, but as I said, thats kind of arbitrary and if you look at the inheritance rules and try to reason from the view of clients with respect to the external interface, then going with public as the chosen modifier also starts to sound reasonable...





    --TEST--
    Conflicting properties with different visibility modifiers should be merged
    to the most restrictive modifier.
    --FILE--
    <?php
    error_reporting(E_ALL);

    trait THello1 {
    public $hello = "foo";
    }

    trait THello2 {
    public $hello = "bar";
    }

    class TraitsTest {
    use THello1;
    use THello2;
    public function getHello() {
    return $this->hello;
    }
    }

    $t = new TraitsTest;
    ?>
    --EXPECTF--
    Fatal error: Conflicting definitions for property TraitsTest::$hello provided by THello1, THello2 in %s on line %d




    Best regards
    Stefan


    --
    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
  • Jonathan Bond-Caron at Dec 18, 2010 at 5:14 pm

    On Sat Dec 18 10:29 AM, Stefan Marr wrote:
    At least I do not find an argument for either way that completely
    convinces me.
    At the moment, the main reason is that 'public' can be considered to
    be the default visibility modifier.
    Based on the semantics of 'var' and dynamic properties.
    Thus, private tends to imply that an additional constraint was
    consciously applied to the property, which should be preserved.
    Well, but as I said, thats kind of arbitrary and if you look at the
    inheritance rules and try to reason from the view of clients with
    respect to the external interface, then going with public as the
    chosen modifier also starts to sound reasonable...
    Does the order of the declaration matter?

    trait THello1 {
    public $foo;
    }

    trait THello2 {
    private $foo;
    }

    trait THello3 {
    protected $foo;
    }

    class TraitsTest {
    use THello1;
    use THello2; // E_NOTICE: TraitTest conflict, THello2(private $foo)
    ignored, already declared THello1(public $foo)
    use THello3; // E_NOTICE: TraitTest conflict, THello3(protected
    $foo) ignored, already declared THello1(public $foo)
    }

    class TraitsTest2 {
    use THello3;
    use THello2; // E_NOTICE: ..
    use THello1; // E_NOTICE: ..
    }

    It could be that the first property 'wins' and an E_NOTICE is raised about
    the property conflict.

    Result:

    class TraitsTest {
    public $foo;
    }

    class TraitsTest2 {
    protected $foo;
    }

    It would seem to fit php, though I'd be happy with simply E_FATAL until
    people start using traits

    The same for:

    trait THelloA {
    public $foo = 'a';
    }
    trait THelloB {
    public $foo = 'b';
    }
    class TraitsTest3 {
    use THelloA;
    use THelloB; // E_NOTICE: TraitTest3 conflict, THelloB(public $foo)
    ignored, already declared THelloA(public $foo)
    }

    class TraitsTest4 {
    use THelloB;
    use THelloA; // E_NOTICE: TraitTest3 conflict, THelloA(public $foo)
    ignored, already declared THelloB(public $foo)
    }

    class TraitsTest5 {
    public $foo = 'c';

    use THelloB; // E_NOTICE: TraitTest3 conflict, THelloB(public $foo)
    ignored, already declared TraitsTest5(public $foo)
    use THelloA; // E_NOTICE: TraitTest3 conflict, THelloA(public $foo)
    ignored, already declared THelloB(public $foo)
    }
  • Stefan Marr at Dec 18, 2010 at 5:34 pm
    Hi Jonathan:
    On 18 Dec 2010, at 18:14, Jonathan Bond-Caron wrote:

    Does the order of the declaration matter?
    No, the order does not matter, and that is one of the key points of traits compared to mixins or Python's way of multiple inheritance.
    So, any kind of order-dependent solution would be inconsistent with the design of traits.
    though I'd be happy with simply E_FATAL until
    people start using traits
    What do you mean by the second part? (until people start using traits)
    Changing the design retrospectively does not seem to be the best option?

    Best regards
    Stefan

    --
    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
  • Jonathan Bond-Caron at Dec 18, 2010 at 7:08 pm

    On Sat Dec 18 12:33 PM, Stefan Marr wrote:
    Hi Jonathan:
    On 18 Dec 2010, at 18:14, Jonathan Bond-Caron wrote:

    Does the order of the declaration matter?
    No, the order does not matter, and that is one of the key points of
    traits compared to mixins or Python's way of multiple inheritance.
    So, any kind of order-dependent solution would be inconsistent with
    the design of traits.
    though I'd be happy with simply E_FATAL until people start using
    traits
    What do you mean by the second part? (until people start using traits)
    Changing the design retrospectively does not seem to be the best
    option?
    Most likely not the best option, I think I'm saying I prefer E_FATAL

    But if users find it too restrictive / problematic, the auto-resolution
    "merge to the most restrictive modifier" could be added in a next release or
    an approach that's convenient to the code out there using traits &
    properties. That seems better than the other way around.
  • Matthew Weier O'Phinney at Dec 19, 2010 at 4:22 pm

    On 2010-12-18, Stefan Marr wrote:
    On 16 Dec 2010, at 23:31, Larry Garfield wrote:
    - When the visibility collides, should we be folding to the most
    restrictive or least restrictive? I'm not sure myself; I'm more
    interested in your reasoning for going for most-restrictive.
    So, in general, I think, there is no 'right thing' to do here, because
    the definitions seem to be incompatible but that is only decidable at
    the application-level.

    There is another, related, edge-case in the test case below. In the
    test we have different initial values for the properties, which makes
    it 'obvious' that they are incompatible. Thus, in that case I would
    argue for a E_COMPILE_ERROR instead of a notice.

    The reason to use the stricter modifier is, well, arbitrary.

    At least I do not find an argument for either way that completely
    convinces me. At the moment, the main reason is that 'public' can be
    considered to be the default visibility modifier. Based on the
    semantics of 'var' and dynamic properties. Thus, private tends to
    imply that an additional constraint was consciously applied to the
    property, which should be preserved.
    I'd argue that traits should follow similar rules to normal class
    inheritance. In that paradigm, you can override a previously defined
    member by using equal or _greater_ visibility only -- i.e., you can't
    make it _less_ visible (e.g., making a property declared as protected in
    the parent class private in the extending class). With traits, it seems
    like we should go with whatever is _most_ visible, as then no matter
    what traits are mixed in, access is guaranteed.
    Well, but as I said, thats kind of arbitrary and if you look at the
    inheritance rules and try to reason from the view of clients with
    respect to the external interface, then going with public as the
    chosen modifier also starts to sound reasonable...
    Exactly. I wouldn't default to public on conflicts, though -- just with
    the highest declared visibility (e.g., if one trait defines as private
    and the other as protected, protected wins).

    --
    Matthew Weier O'Phinney
    Project Lead | matthew@zend.com
    Zend Framework | http://framework.zend.com/
    PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc
  • Stefan Marr at Dec 19, 2010 at 7:04 pm
    Hi Matthew:
    On 19 Dec 2010, at 17:22, Matthew Weier O'Phinney wrote:
    Exactly. I wouldn't default to public on conflicts, though -- just with
    the highest declared visibility (e.g., if one trait defines as private
    and the other as protected, protected wins).
    I am currently actually implementing the most restricted proposal: all differences in the property definition will lead to a fatal error.

    The reasoning behind this is, that the semantics of state is not predictable and all changes in the class/traits hierarchies which are incompatible should give the developer an immediate feedback, i.e., make potentially incompatible code break.
    That is not the most 'dynamic' of all possible solutions but seems to fit with the rest of PHP.

    What I have in mind is also not how the methods integrate into the inheritance chain, thus, a property in the body of the class does not override all property definitions in traits (this is the case for methods).
    I think that will be useful for the very same reason. And well, I hope an educative error message will steer the crowed in the right direction to use accessors.

    Best regards
    Stefan


    --
    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
  • Matthew Weier O'Phinney at Dec 20, 2010 at 1:53 pm

    On 2010-12-19, Stefan Marr wrote:
    On 19 Dec 2010, at 17:22, Matthew Weier O'Phinney wrote:
    Exactly. I wouldn't default to public on conflicts, though -- just with
    the highest declared visibility (e.g., if one trait defines as private
    and the other as protected, protected wins).
    I am currently actually implementing the most restricted proposal: all
    differences in the property definition will lead to a fatal error.

    The reasoning behind this is, that the semantics of state is not
    predictable and all changes in the class/traits hierarchies which are
    incompatible should give the developer an immediate feedback, i.e.,
    make potentially incompatible code break. That is not the most
    'dynamic' of all possible solutions but seems to fit with the rest of
    PHP.
    That makes sense to me as well; having conflicting properties due to
    multiple traits implementing them is a good way to lead to inconsistency
    and difficult to test/predict code.
    What I have in mind is also not how the methods integrate into the
    inheritance chain, thus, a property in the body of the class does not
    override all property definitions in traits (this is the case for
    methods). I think that will be useful for the very same reason. And
    well, I hope an educative error message will steer the crowed in the
    right direction to use accessors.
    --
    Matthew Weier O'Phinney
    Project Lead | matthew@zend.com
    Zend Framework | http://framework.zend.com/
    PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc
  • Larry at Dec 20, 2010 at 4:04 pm

    On 12/20/10 7:53 AM, Matthew Weier O'Phinney wrote:
    On 2010-12-19, Stefan Marrwrote:
    On 19 Dec 2010, at 17:22, Matthew Weier O'Phinney wrote:
    Exactly. I wouldn't default to public on conflicts, though -- just with
    the highest declared visibility (e.g., if one trait defines as private
    and the other as protected, protected wins).
    I am currently actually implementing the most restricted proposal: all
    differences in the property definition will lead to a fatal error.

    The reasoning behind this is, that the semantics of state is not
    predictable and all changes in the class/traits hierarchies which are
    incompatible should give the developer an immediate feedback, i.e.,
    make potentially incompatible code break. That is not the most
    'dynamic' of all possible solutions but seems to fit with the rest of
    PHP.
    That makes sense to me as well; having conflicting properties due to
    multiple traits implementing them is a good way to lead to inconsistency
    and difficult to test/predict code.
    I will agree up to a point. "Dude, this will probably break" is a
    worthwhile message to give. At the same time, though, there does need
    to be a way for the developer to say "I know that; trust me, I know what
    I'm doing". Otherwise, having two traits that are supposed to operate
    on the same base data will become needlessly complicated with
    return-by-ref accessors that may also collide.

    E.g., if I have three traits that all operate on an internal array, and
    a dozen classes that use them, I do want class A to have traits 1 and 2,
    class B to have traits 1 and 3, etc., without needing three extra
    accessors lying around that serve no purpose other than to work around
    an unnecessary PHP restriction. (Stack calls in PHP are not free, aside
    from the ugly code that results in.)

    Perhaps if both traits use the same variable name, visibility, *and*
    default value then there is no error?

    I suspect this issue dovetails with the Traits-and-interfaces thread
    from earlier.

    --Larry Garfield
  • Stefan Marr at Dec 20, 2010 at 11:21 pm
    Hi Larry:
    On 20 Dec 2010, at 17:04, larry@garfieldtech.com wrote:

    Perhaps if both traits use the same variable name, visibility, *and* default value then there is no error?
    There is not fatal error, however, currently there is E_STRICT notice.

    I suspect this issue dovetails with the Traits-and-interfaces thread from earlier.
    Ehm, not sure what you want to get at.
    The idea of expressing that the composing class needs to satisfy an interface, or perhaps inherit from a specific class still seems to have a number of valid use cases.
    However, there was a single strong opinion against it, as far as I remember.

    Anyway, on the topic of properties.
    For the records, I updated the RFC with the following section.

    http://wiki.php.net/rfc/horizontalreuse#handling_of_propertiesstate

    Comments are welcome.
    Thanks
    Stefan

    ===== Handling of Properties/State =====

    Traits do not provide any provisioning for handling state.
    They are meant to provide a light-weight mechanism for flexible code reuse,
    with the mean goal being to avoid code duplication.
    Moreover, should not be confused with typical use cases of classes.
    When a strong coherence/coupling between methods and state is required,
    and certain invariants have to be maintained on the state, this is a good
    indication that a class is the right abstraction to implement that problem
    with.

    However, every behavior needs state to operate on, otherwise it could be just
    a static functional helper method.
    Thus, trait code will either need to use accessors, which is favorite way to
    go since it provides full traits semantics, or they use properties, which
    is possible but rather a convenience feature.

    Since state is a complex problem, and the knowledge about compatibility of
    state form different traits is only present in a concrete composition, proper
    state handling would need language features which are currently considered
    beyond the scope of what is necessary for PHP. (See [[http://scg.unibe.ch/archive/papers/Berg07eStatefulTraits.pdf|Bergel et al]])

    Thus, the goal for a consistent language design is to raise awareness of the
    problem, promote the use of accessors, and break early in case the changes to
    a trait is potentially problematic for a class using it. This results in the
    following rules:

    - Properties are considered incompatible if they differ in their definition.
    This means, they differ in the applied modifiers (static, public,
    protected, private) or their initial value.
    - Incompatible properties result in a fatal error.
    - In all other cases, i.e., when the definitions are identical, an E_STRICT
    notice is shown to raise awareness about the potentially problematic, and
    discouraged use of properties.
    - For those checks, all properties are treated equal. Properties from the
    base class and the composing class have to be compatible with properties
    from traits as well as the properties between all traits have to be
    compatible.
    - Non-coliding properties, and properties which are not considered
    incompatible behave exactly the same as if they would have been defined
    in the composing class.

    This property handling was implemented in [[http://svn.php.net/viewvc?view=revision&revision=306476|SVN revision 306476]] and examples are given in the test cases.



    --Larry Garfield

    --
    PHP Internals - PHP Runtime Development Mailing List
    To unsubscribe, visit: http://www.php.net/unsub.php
    --
    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
  • Larry Garfield at Dec 21, 2010 at 2:23 am

    On Monday, December 20, 2010 5:21:08 pm Stefan Marr wrote:
    Hi Larry:
    On 20 Dec 2010, at 17:04, larry@garfieldtech.com wrote:
    Perhaps if both traits use the same variable name, visibility, *and*
    default value then there is no error?
    There is not fatal error, however, currently there is E_STRICT notice.
    I suspect this issue dovetails with the Traits-and-interfaces thread from
    earlier.
    Ehm, not sure what you want to get at.
    The idea of expressing that the composing class needs to satisfy an
    interface, or perhaps inherit from a specific class still seems to have a
    number of valid use cases. However, there was a single strong opinion
    against it, as far as I remember.
    I mean, for instance, if you're using an accessor method then you need that
    accessor to exist, because you're hard coding its name. If you instead
    provide the accessor yourself, the accessor will be hard coded to a variable
    name, whether you provide it or not. So either way your trait will die if the
    including class doesn't provide some supporting something.

    Example:

    Trait Foo1 {
    function increment() {
    // Implicit requirement that a class have a property named foo.
    $this->foo++;
    }
    }

    Trait Foo2 {
    // Implicit requirement that a class NOT a property named foo.
    protected $foo;

    function increment() {
    $this->foo++;
    }
    }

    Trait Foo3 {
    function increment() {
    $foo = &$this->getFoo();
    $foo++;
    }
    function &getFoo() {
    // Implicit requirement that a class have a property named foo.
    return $this->foo;
    }
    }

    Trait Foo4 {
    function increment() {
    // Implicit requirement that a class have a method named getFoo().
    $foo = &$this->getFoo();
    $foo++;
    }
    }

    class Test {
    use Foo;
    }

    So one way or another, there is always an implicit requirement placed on the
    using class. Implicit requirements suck. :-) If the answer to trait-based
    properties is "if it breaks when you do that, don't do that" (which I don't
    fully agree with, in part because of how ugly lots of return-by-ref methods
    is), then we have to make the methods as easy as possible. Requiring an
    interface is one proposed way to do that.

    Reading the RFC over again, I actually see that there is support for abstract
    methods in a trait. I suppose that serves a similar purpose of causing a
    compile-time error (and thus something much more obvious to be fixed), and
    becomes becomes a matter of taste to a degree.

    I don't believe the RFC mentions how those resolve in case of collision,
    though. If two traits define the same abstract method, does that cause a
    collision that needs manual resolution or can the using class just define it
    once and thereby support both traits?

    --Larry Garfield
  • Stefan Marr at Jan 6, 2011 at 1:43 pm
    Hi Larry:
    On 21 Dec 2010, at 03:24, Larry Garfield wrote:

    I don't believe the RFC mentions how those resolve in case of collision,
    though. If two traits define the same abstract method, does that cause a
    collision that needs manual resolution or can the using class just define it
    once and thereby support both traits?
    Abstract methods do not cause collisions, no. So, there can be an arbitrary number of traits asking for an abstract method with identical name, and the only thing that has to happen is that it is implemented eventually, perhaps by another trait.

    Best regards
    Stefan

    --
    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
  • Jonathan Bond-Caron at Dec 22, 2010 at 3:39 pm

    On Mon Dec 20 06:21 PM, Stefan Marr wrote:

    ===== Handling of Properties/State =====

    This property handling was implemented in
    [[http://svn.php.net/viewvc?view=revision&revision=306476|SVN revision
    306476]] and examples are given in the test cases.
    +1

    The E_STRICT warning seems to follow nicely the paper's view that a stateful
    trait should be its own 'black-box':
    http://scg.unibe.ch/archive/papers/Berg07eStatefulTraits.pdf

    There are two remaining questions I have:
    1) How do traits affect the reflection API?
    2) Do we want to be able to declare trait requirements for properties and
    methods? If so what syntax?

    A note on the syntax proposed by Nathan:
    trait require Foo

    An option could be:

    trait Foo {
    require {
    public $var;
    function ratio();
    }

    function doFoo($v) {
    $this->var = $v * $this->ratio();
    }
    }

    trait Bar {
    require interface Iterator;
    }

    The idea comes from:
    http://code.google.com/p/es-lab/wiki/Traits

    I found this trying to look for alternative keyword for 'require'.
  • Stefan Marr at Jan 6, 2011 at 1:38 pm
    Hi Jonathan:

    Sorry, was not able to get back to those discussions earlier.

    On 22 Dec 2010, at 16:39, Jonathan Bond-Caron wrote:

    There are two remaining questions I have:
    1) How do traits affect the reflection API?
    Johannes implemented some features in the Reflection API.

    However, they are very ad-hoc, and there are some points which could be designed differently to make the concepts more clear.

    On of those things is that you actually use ReflectionClass to reflect on a trait.
    That is really an implementation detail, and should be changed to not confuse anyone on a conceptional level. We should not expose that kind of engine/implementation detail.

    Thus, there remains stuff to be done about reflection. In general, I would like to be able to access all information that was in the source code. However, time constraints are an issue for me. If there would be a new release date for an alpha or something, I think I could get some time to work on it...

    2) Do we want to be able to declare trait requirements for properties and
    methods? If so what syntax?
    Well, there was the proposal to use require to express constraints for the composing class, which is something I liked.

    However, I would not go to support properties, too, since I still maintain the opinion that we do not actually do something about state with regard to traits.

    A note on the syntax proposed by Nathan:
    trait require Foo

    An option could be:

    trait Foo {
    require {
    public $var;
    function ratio();
    }
    Hm, well, we already got abstract methods for the methods part.

    trait Bar {
    require interface Iterator;
    }
    And expressing the requirement for an interface or an abstract class seems to be the only thing missing, I think.

    However, I would not put that in the body but into the hat.

    trait Bar require OneSpecificClass, AndPossiblyAnInterface, OrPossiblyAnotherInterface {}

    The idea comes from:
    http://code.google.com/p/es-lab/wiki/Traits

    I found this trying to look for alternative keyword for 'require'.
    Yes, Tom worked on that a while ago, but it was to easy to implement it in a library for JavaScript. To easy to be considered for a language feature...

    Best regards
    Stefan

    --
    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
  • Johannes Schlüter at Jan 6, 2011 at 2:33 pm

    On Thu, 2011-01-06 at 14:38 +0100, Stefan Marr wrote:

    On of those things is that you actually use ReflectionClass to reflect
    on a trait.
    That is really an implementation detail, and should be changed to not
    confuse anyone on a conceptional level. We should not expose that kind
    of engine/implementation detail.
    This is the same with interfaces. What does class_exists('some_trait')
    do? - I assume that returns true too.
    Thus, there remains stuff to be done about reflection. In general, I
    would like to be able to access all information that was in the source
    code. However, time constraints are an issue for me. If there would be
    a new release date for an alpha or something, I think I could get some
    time to work on it...
    I hoped to do some work on it over Christmas vacation, too, but did
    other stuff in the end ...

    johannes
  • Stefan Marr at Jan 9, 2011 at 4:24 pm

    On 06 Jan 2011, at 15:33, Johannes Schlüter wrote:
    On Thu, 2011-01-06 at 14:38 +0100, Stefan Marr wrote:

    On of those things is that you actually use ReflectionClass to reflect
    on a trait.
    That is really an implementation detail, and should be changed to not
    confuse anyone on a conceptional level. We should not expose that kind
    of engine/implementation detail.
    This is the same with interfaces. What does class_exists('some_trait')
    do? - I assume that returns true too.
    It does return false for interfaces, that should be consistent and return false for traits, too.

    Best regards
    Stefan

    --
    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
  • Stefan Marr at Jan 9, 2011 at 9:14 pm
    Hi:
    On 09 Jan 2011, at 17:23, Stefan Marr wrote:

    This is the same with interfaces. What does class_exists('some_trait')
    do? - I assume that returns true too.
    It does return false for interfaces, that should be consistent and return false for traits, too.
    Ok, that is fixed and I added a trait_exists() to match the other functions.

    Will add a note to the RFC.

    Best regards
    Stefan


    --
    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
  • Stefan Marr at Dec 16, 2010 at 3:25 pm
    Hi:

    From my point of view the right thing to do with regard to properties is defined in the test cases below.

    The rational behind providing this semantics is based on the fact that PHP allows to define properties dynamically anyway, so there is no way around properties.
    However, there should be a way that a developer can notice that the code might not behave as expected in the composed class.

    It is true that behavior needs state to operate on, however, accessors are a common pattern and fully supported by traits. Furthermore, traits are not supposed to replace classes, and when a trait does more than just providing code that is to be easily reused, then the designed should ask the question whether that is not actually a class, which then provides the necessary guarantees to enforce the invariances the code expects.

    Thus, I would like to keep traits as a lightweight concept for code reuse.

    Best regards
    Stefan

    --TEST--
    Conflicting properties should result in a notice.
    Property use is discorage for traits that are supposed to enable maintainable
    code reuse. Accessor methods are the language supported idiom for this.
    --FILE--
    <?php
    error_reporting(E_ALL);

    trait THello1 {
    public $foo;
    }

    trait THello2 {
    private $foo;
    }

    class TraitsTest {
    use THello1;
    use THello2;
    }

    var_dump(property_exists('TraitsTest', 'foo'));
    ?>
    --EXPECTF--
    Notice: Trait THello1 and THello2 define the same property in the composition of TraitsTest. This might be incompatible, to improve maintainability consider using accessor methods instead. Class was composed in %s on line %d.

    bool(true)




    --TEST--
    Non-conflicting properties should work just fine.
    --FILE--
    <?php
    error_reporting(E_ALL);

    trait THello1 {
    public $hello = "hello";
    }

    trait THello2 {
    private $world = "World!";
    }

    class TraitsTest {
    use THello1;
    use THello2;
    function test() {
    echo $this->hello . ' ' . $this->world;
    }
    }

    var_dump(property_exists('TraitsTest', 'hello'));
    var_dump(property_exists('TraitsTest', 'world'));

    $t = new TraitsTest;
    $t->test();
    ?>
    --EXPECTF--
    bool(true)
    bool(true)

    hello World!


    --TEST--
    Conflicting properties with different visibility modifiers should be merged
    to the most restrictive modifier.
    --FILE--
    <?php
    error_reporting(E_ALL);

    trait THello1 {
    public $hello;
    }

    trait THello2 {
    private $hello;
    }

    class TraitsTest {
    use THello1;
    use THello2;
    }

    $t = new TraitsTest;
    $t->hello = "foo";
    ?>
    --EXPECTF--
    Fatal error: Cannot access private property TraitsTest::$foo in %s on line %d
    On 11 Dec 2010, at 17:47, Stefan Marr wrote:

    Hi:

    Traits do not provide any special provisioning for handling properties, especially, there is no language solution for handling colliding property names.
    The current solution/idiom for handling state safely in a trait is to use either abstract set/get methods or an abstract get that returns a reference to the property in the class.

    However, at the moment it is possible to define properties in a trait:

    trait Foo {
    private $a;
    public $foo;
    }

    For the moment, that information is completely ignored, thus:

    class Bar {
    use Foo;
    }
    property_exists('Bar', 'a') === false


    Well, and that is a rather inconsistent status-quo.

    I would like to have that fixed in one or another way.

    One possibility would be to forbid property definition in a trait altogether.
    That reduces a bit the possibility to have wrong expectations about properties, however, the dynamic property creation is still possible.

    Another way would be to merge the properties in the composing class.
    The question here would be how to treat visibility modifiers: how to merge public and private, should it result in public, or private?
    And, to discorage users to go this way, should there be a STRICT notice? Options here are a notice whenever a property is defined in a trait, or whenever properties are silently merged.


    Comments very welcome.

    Thanks
    Stefan

    --
    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


    --
    PHP Internals - PHP Runtime Development Mailing List
    To unsubscribe, visit: http://www.php.net/unsub.php
    --
    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
  • Sebastian Bergmann at Dec 16, 2010 at 3:59 pm

    Am 16.12.2010 16:25, schrieb Stefan Marr:
    From my point of view the right thing to do with regard to
    properties is defined in the test cases below.
    +1

    --
    Sebastian Bergmann Co-Founder and Principal Consultant
    http://sebastian-bergmann.de/ http://thePHP.cc/
  • Benjamin Eberlei at Dec 16, 2010 at 4:01 pm
    I like it,

    additionally if you want to prevent conflicts from the start you can
    always go and define prefixed property names like below and use a getter to
    access them conveniently.

    trait Foo
    {
    private $Foo_prop;

    public function getProp()
    {
    return $this->Foo_prop;
    }
    }

    I am really looking forward to traits in 5.4!

    greetings,
    Benjamin
    On Thu, 16 Dec 2010 16:25:42 +0100, Stefan Marr wrote:
    Hi:

    From my point of view the right thing to do with regard to properties is
    defined in the test cases below.

    The rational behind providing this semantics is based on the fact that PHP
    allows to define properties dynamically anyway, so there is no way around
    properties.
    However, there should be a way that a developer can notice that the code
    might not behave as expected in the composed class.

    It is true that behavior needs state to operate on, however, accessors are
    a common pattern and fully supported by traits. Furthermore, traits are not
    supposed to replace classes, and when a trait does more than just providing
    code that is to be easily reused, then the designed should ask the question
    whether that is not actually a class, which then provides the necessary
    guarantees to enforce the invariances the code expects.

    Thus, I would like to keep traits as a lightweight concept for code reuse.
    Best regards
    Stefan

    --TEST--
    Conflicting properties should result in a notice.
    Property use is discorage for traits that are supposed to enable
    maintainable
    code reuse. Accessor methods are the language supported idiom for this.
    --FILE--
    <?php
    error_reporting(E_ALL);

    trait THello1 {
    public $foo;
    }

    trait THello2 {
    private $foo;
    }

    class TraitsTest {
    use THello1;
    use THello2;
    }

    var_dump(property_exists('TraitsTest', 'foo'));
    ?>
    --EXPECTF--
    Notice: Trait THello1 and THello2 define the same property in the
    composition of TraitsTest. This might be incompatible, to improve
    maintainability consider using accessor methods instead. Class was composed
    in %s on line %d.

    bool(true)




    --TEST--
    Non-conflicting properties should work just fine.
    --FILE--
    <?php
    error_reporting(E_ALL);

    trait THello1 {
    public $hello = "hello";
    }

    trait THello2 {
    private $world = "World!";
    }

    class TraitsTest {
    use THello1;
    use THello2;
    function test() {
    echo $this->hello . ' ' . $this->world;
    }
    }

    var_dump(property_exists('TraitsTest', 'hello'));
    var_dump(property_exists('TraitsTest', 'world'));

    $t = new TraitsTest;
    $t->test();
    ?>
    --EXPECTF--
    bool(true)
    bool(true)

    hello World!


    --TEST--
    Conflicting properties with different visibility modifiers should be merged
    to the most restrictive modifier.
    --FILE--
    <?php
    error_reporting(E_ALL);

    trait THello1 {
    public $hello;
    }

    trait THello2 {
    private $hello;
    }

    class TraitsTest {
    use THello1;
    use THello2;
    }

    $t = new TraitsTest;
    $t->hello = "foo";
    ?>
    --EXPECTF--
    Fatal error: Cannot access private property TraitsTest::$foo in %s on line
    %d
    On 11 Dec 2010, at 17:47, Stefan Marr wrote:

    Hi:

    Traits do not provide any special provisioning for handling properties,
    especially, there is no language solution for handling colliding
    property
    names.
    The current solution/idiom for handling state safely in a trait is to
    use either abstract set/get methods or an abstract get that returns a
    reference to the property in the class.

    However, at the moment it is possible to define properties in a trait:

    trait Foo {
    private $a;
    public $foo;
    }

    For the moment, that information is completely ignored, thus:

    class Bar {
    use Foo;
    }
    property_exists('Bar', 'a') === false


    Well, and that is a rather inconsistent status-quo.

    I would like to have that fixed in one or another way.

    One possibility would be to forbid property definition in a trait
    altogether.
    That reduces a bit the possibility to have wrong expectations about
    properties, however, the dynamic property creation is still possible.

    Another way would be to merge the properties in the composing class.
    The question here would be how to treat visibility modifiers: how to
    merge public and private, should it result in public, or private?
    And, to discorage users to go this way, should there be a STRICT
    notice?
    Options here are a notice whenever a property is defined in a trait, or
    whenever properties are silently merged.


    Comments very welcome.

    Thanks
    Stefan

    --
    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


    --
    PHP Internals - PHP Runtime Development Mailing List
    To unsubscribe, visit: http://www.php.net/unsub.php
    --
    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
  • Matthew Weier O'Phinney at Dec 16, 2010 at 5:49 pm

    On 2010-12-16, Stefan Marr wrote:
    From my point of view the right thing to do with regard to properties
    is defined in the test cases below.

    The rational behind providing this semantics is based on the fact that
    PHP allows to define properties dynamically anyway, so there is no way
    around properties. However, there should be a way that a developer
    can notice that the code might not behave as expected in the composed
    class.
    +1

    The test cases you include are exactly how I would expect traits to work
    with regards to properties.

    --
    Matthew Weier O'Phinney
    Project Lead | matthew@zend.com
    Zend Framework | http://framework.zend.com/
    PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc
  • Patrick ALLAERT at Dec 16, 2010 at 9:05 pm

    2010/12/16 Stefan Marr <php@stefan-marr.de>:
    Hi:

    From my point of view the right thing to do with regard to properties is defined in the test cases below.

    The rational behind providing this semantics is based on the fact that PHP allows to define properties dynamically anyway, so there is no way around properties.
    However, there should be a way that a developer can notice that the code might not behave as expected in the composed class.

    It is true that behavior needs state to operate on, however, accessors are a common pattern and fully supported by traits. Furthermore, traits are not supposed to replace classes, and when a trait does more than just providing code that is to be easily reused, then the designed should ask the question whether that is not actually a class, which then provides the necessary guarantees to enforce the invariances the code expects.

    Thus, I would like to keep traits as a lightweight concept for code reuse.

    Best regards
    Stefan

    --TEST--
    Conflicting properties should result in a notice.
    Property use is discorage for traits that are supposed to enable maintainable
    code reuse. Accessor methods are the language supported idiom for this.
    --FILE--
    <?php
    error_reporting(E_ALL);

    trait THello1 {
    public $foo;
    }

    trait THello2 {
    private $foo;
    }

    class TraitsTest {
    use THello1;
    use THello2;
    }

    var_dump(property_exists('TraitsTest', 'foo'));
    ?>
    --EXPECTF--
    Notice: Trait THello1 and THello2 define the same property in the composition of TraitsTest. This might be incompatible, to improve maintainability consider using accessor methods instead. Class was composed in %s on line %d.
    In this test, you might want to display some text before the
    var_dump() (or alternatively to hardcode the line number on last line)
    to ensure it is the property_exists() function call or the class
    definition which would create such a notice.

    Regards,
    Patrick

    --
    Patrick Allaert
    ---
    http://code.google.com/p/peclapm/ - Alternative PHP Monitor
  • Larry at Dec 16, 2010 at 10:32 pm
    I am fine with this approach, with 2 caveats:

    - If you actually do want to make two traits use the same property, it
    looks like the answer here is "Either have no property and demand the
    existence of an accessor that returns by reference, or you can't write
    E_NOTICE-safe code". Is that true?

    - When the visibility collides, should we be folding to the most
    restrictive or least restrictive? I'm not sure myself; I'm more
    interested in your reasoning for going for most-restrictive.

    --Larry Garfield
    On 12/16/10 9:25 AM, Stefan Marr wrote:
    Hi:

    From my point of view the right thing to do with regard to properties is defined in the test cases below.

    The rational behind providing this semantics is based on the fact that PHP allows to define properties dynamically anyway, so there is no way around properties.
    However, there should be a way that a developer can notice that the code might not behave as expected in the composed class.

    It is true that behavior needs state to operate on, however, accessors are a common pattern and fully supported by traits. Furthermore, traits are not supposed to replace classes, and when a trait does more than just providing code that is to be easily reused, then the designed should ask the question whether that is not actually a class, which then provides the necessary guarantees to enforce the invariances the code expects.

    Thus, I would like to keep traits as a lightweight concept for code reuse.

    Best regards
    Stefan

    --TEST--
    Conflicting properties should result in a notice.
    Property use is discorage for traits that are supposed to enable maintainable
    code reuse. Accessor methods are the language supported idiom for this.
    --FILE--
    <?php
    error_reporting(E_ALL);

    trait THello1 {
    public $foo;
    }

    trait THello2 {
    private $foo;
    }

    class TraitsTest {
    use THello1;
    use THello2;
    }

    var_dump(property_exists('TraitsTest', 'foo'));
    ?>
    --EXPECTF--
    Notice: Trait THello1 and THello2 define the same property in the composition of TraitsTest. This might be incompatible, to improve maintainability consider using accessor methods instead. Class was composed in %s on line %d.

    bool(true)




    --TEST--
    Non-conflicting properties should work just fine.
    --FILE--
    <?php
    error_reporting(E_ALL);

    trait THello1 {
    public $hello = "hello";
    }

    trait THello2 {
    private $world = "World!";
    }

    class TraitsTest {
    use THello1;
    use THello2;
    function test() {
    echo $this->hello . ' ' . $this->world;
    }
    }

    var_dump(property_exists('TraitsTest', 'hello'));
    var_dump(property_exists('TraitsTest', 'world'));

    $t = new TraitsTest;
    $t->test();
    ?>
    --EXPECTF--
    bool(true)
    bool(true)

    hello World!


    --TEST--
    Conflicting properties with different visibility modifiers should be merged
    to the most restrictive modifier.
    --FILE--
    <?php
    error_reporting(E_ALL);

    trait THello1 {
    public $hello;
    }

    trait THello2 {
    private $hello;
    }

    class TraitsTest {
    use THello1;
    use THello2;
    }

    $t = new TraitsTest;
    $t->hello = "foo";
    ?>
    --EXPECTF--
    Fatal error: Cannot access private property TraitsTest::$foo in %s on line %d
    On 11 Dec 2010, at 17:47, Stefan Marr wrote:

    Hi:

    Traits do not provide any special provisioning for handling properties, especially, there is no language solution for handling colliding property names.
    The current solution/idiom for handling state safely in a trait is to use either abstract set/get methods or an abstract get that returns a reference to the property in the class.

    However, at the moment it is possible to define properties in a trait:

    trait Foo {
    private $a;
    public $foo;
    }

    For the moment, that information is completely ignored, thus:

    class Bar {
    use Foo;
    }
    property_exists('Bar', 'a') === false


    Well, and that is a rather inconsistent status-quo.

    I would like to have that fixed in one or another way.

    One possibility would be to forbid property definition in a trait altogether.
    That reduces a bit the possibility to have wrong expectations about properties, however, the dynamic property creation is still possible.

    Another way would be to merge the properties in the composing class.
    The question here would be how to treat visibility modifiers: how to merge public and private, should it result in public, or private?
    And, to discorage users to go this way, should there be a STRICT notice? Options here are a notice whenever a property is defined in a trait, or whenever properties are silently merged.


    Comments very welcome.

    Thanks
    Stefan

    --
    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


    --
    PHP Internals - PHP Runtime Development Mailing List
    To unsubscribe, visit: http://www.php.net/unsub.php
  • David Muir at Jan 3, 2011 at 3:24 am

    On 12/12/10 01:47, Stefan Marr wrote:
    Hi:

    Traits do not provide any special provisioning for handling properties, especially, there is no language solution for handling colliding property names.
    The current solution/idiom for handling state safely in a trait is to use either abstract set/get methods or an abstract get that returns a reference to the property in the class.

    However, at the moment it is possible to define properties in a trait:

    trait Foo {
    private $a;
    public $foo;
    }

    For the moment, that information is completely ignored, thus:

    class Bar {
    use Foo;
    }
    property_exists('Bar', 'a') === false


    Well, and that is a rather inconsistent status-quo.

    I would like to have that fixed in one or another way.

    One possibility would be to forbid property definition in a trait altogether.
    That reduces a bit the possibility to have wrong expectations about properties, however, the dynamic property creation is still possible.

    Another way would be to merge the properties in the composing class.
    The question here would be how to treat visibility modifiers: how to merge public and private, should it result in public, or private?
    And, to discorage users to go this way, should there be a STRICT notice? Options here are a notice whenever a property is defined in a trait, or whenever properties are silently merged.


    Comments very welcome.

    Thanks
    Stefan
    What about extending the way that traits resolve method conflicts to
    solve property conflicts in a similar fashion? I can't remember if it's
    already been suggested and and maybe shot down already. It would
    probably get horrendously messy, but figured I'd mention it anyway.

    Cheers,
    David
  • Ben Schmidt at Jan 3, 2011 at 5:58 am

    On 3/01/11 2:24 PM, David Muir wrote:
    On 12/12/10 01:47, Stefan Marr wrote:
    Hi:

    Traits do not provide any special provisioning for handling properties,
    especially, there is no language solution for handling colliding property names.
    The current solution/idiom for handling state safely in a trait is to use either
    abstract set/get methods or an abstract get that returns a reference to the
    property in the class.

    However, at the moment it is possible to define properties in a trait:

    trait Foo {
    private $a;
    public $foo;
    }

    For the moment, that information is completely ignored, thus:

    class Bar {
    use Foo;
    }
    property_exists('Bar', 'a') === false


    Well, and that is a rather inconsistent status-quo.

    I would like to have that fixed in one or another way.

    One possibility would be to forbid property definition in a trait altogether.
    That reduces a bit the possibility to have wrong expectations about properties,
    however, the dynamic property creation is still possible.

    Another way would be to merge the properties in the composing class.
    The question here would be how to treat visibility modifiers: how to merge
    public and private, should it result in public, or private?
    And, to discorage users to go this way, should there be a STRICT notice? Options
    here are a notice whenever a property is defined in a trait, or whenever
    properties are silently merged.


    Comments very welcome.

    Thanks
    Stefan
    What about extending the way that traits resolve method conflicts to solve
    property conflicts in a similar fashion? I can't remember if it's already been
    suggested and and maybe shot down already. It would probably get horrendously
    messy, but figured I'd mention it anyway.

    Cheers,
    David
    I'm a latecomer here, but...

    Stefan, doesn't this conflict with what you've written here (and the
    test cases in SVN)?:

    http://wiki.php.net/rfc/horizontalreuse#handling_of_propertiesstate

    Or is what is happening here that the properties in traits are treated
    essentially as declarations rather than definitions, triggering errors
    but not actually creating properties, and you think they should actually
    create properties?

    Ben.
  • Stefan Marr at Jan 3, 2011 at 8:50 am
    Hi Ben:
    On 03 Jan 2011, at 06:58, Ben Schmidt wrote:
    I'm a latecomer here, but...

    Stefan, doesn't this conflict with what you've written here (and the
    test cases in SVN)?:

    http://wiki.php.net/rfc/horizontalreuse#handling_of_propertiesstate

    Or is what is happening here that the properties in traits are treated
    essentially as declarations rather than definitions, triggering errors
    but not actually creating properties, and you think they should actually
    create properties?
    Sorry, I do not understand.

    Is the text in the RFC contradicting or not clear enough about what the test cases show?

    The intention was to provide the developer with hints when it is possible that state is incompatible.

    Until now, the reason why there is not fancy mechanism for conflict resolution for properties in traits is, first, the dynamic nature of PHP which makes certain things like 'renaming' inconsistent with the rest of the language, especially its meta-programming facilities, and second, the added problem with state, that you actually have many usecases where the state needs to be merged. However, merging behavior is not possible, which simplifies the language constructs for handling behavioral conflicts.

    Best regards
    Stefan



    --
    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
  • Ben Schmidt at Jan 3, 2011 at 9:04 am
    Hi, Stefan,
    Sorry, I do not understand.
    Haha. Now we are both confused!

    In this email thread you seemed to be saying that properties defined in
    traits are completely ignored, but in the RFC and svn it seems to be
    saying that properties in traits are not ignored, but are merged into
    the class and/or trigger errors/warnings. So, which is it? Ignored or
    not? Or is some aspect of them ignored and some aspect not?

    I hope I'm not making things more confusing....

    Cheers,

    Ben.
  • Stefan Marr at Jan 3, 2011 at 9:16 am
    Hi Ben:
    On 03 Jan 2011, at 10:04, Ben Schmidt wrote:

    In this email thread you seemed to be saying that properties defined in
    traits are completely ignored, but in the RFC and svn it seems to be
    saying that properties in traits are not ignored, but are merged into
    the class and/or trigger errors/warnings. So, which is it? Ignored or
    not? Or is some aspect of them ignored and some aspect not?
    The RFC was discussed on this list, and the RFC should explain what the current state of the implementation is. So, the RFC and the implementation are the specifications. In case they differ it has to be fixed.

    With regard to state, from my academic point of view, it is not handled, however, the language should be now in a shape which provides my interpretation of 'expected behavior' with regard to property definitions.
    When they collide, you get a notice, but the language does not help you in solving the problem.

    Best regards
    Stefan

    --
    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
  • Ben Schmidt at Jan 3, 2011 at 9:35 am
    Hi, Stefan,
    On 3/01/11 8:16 PM, Stefan Marr wrote:
    On 03 Jan 2011, at 10:04, Ben Schmidt wrote:
    In this email thread you seemed to be saying that properties defined in
    traits are completely ignored, but in the RFC and svn it seems to be
    saying that properties in traits are not ignored, but are merged into
    the class and/or trigger errors/warnings. So, which is it? Ignored or
    not? Or is some aspect of them ignored and some aspect not?
    The RFC was discussed on this list, and the RFC should explain what
    the current state of the implementation is. So, the RFC and the
    implementation are the specifications. In case they differ it has to
    be fixed.
    OK. So this comment from your email is outdated?:
    However, at the moment it is possible to define properties in a trait:

    trait Foo {
    private $a;
    public $foo;
    }

    For the moment, that information is completely ignored, thus:

    class Bar {
    use Foo;
    }
    property_exists('Bar', 'a') === false
    in light of this test:

    http://svn.php.net/viewvc/php/php-src/trunk/Zend/tests/traits/property002.phpt?view=markup&pathrev=306476

    Maybe the only thing that was confusing is that somebody replied to an
    old email?

    Ben.
  • Stefan Marr at Jan 3, 2011 at 9:57 am
    Hi Ben:
    On 03 Jan 2011, at 10:35, Ben Schmidt wrote:

    OK. So this comment from your email is outdated?:
    Yes, outdated since this email:
    http://marc.info/?l=php-internals&m=129288735205036&w=2

    Best regards
    Stefan

    --
    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
  • Ben Schmidt at Jan 3, 2011 at 10:16 am

    On 3/01/11 8:57 PM, Stefan Marr wrote:
    Hi Ben:
    On 03 Jan 2011, at 10:35, Ben Schmidt wrote:

    OK. So this comment from your email is outdated?:
    Yes, outdated since this email:
    http://marc.info/?l=php-internals&m=129288735205036&w=2

    Best regards
    Stefan
    OK, Stefan, I just got confused by reading your outdated message that was quoted
    in a recent reply, and by the fact that the "last update" date of 2010-11-18 at
    the top of the RFC is inaccurate, so I assumed the email was more current than it
    was. Seems like the RFC was actually updated circa 2010-12-20. :-)

    Sorry for the noise, guys.

    Ben.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupphp-internals @
categoriesphp
postedDec 11, '10 at 4:47p
activeJan 9, '11 at 9:14p
posts43
users13
websitephp.net

People

Translate

site design / logo © 2022 Grokbase