Well crap I just realised I hadn’t hit reply-all several replies ago!.

I also just noticed that you had mentioned about allowing property writes only 
in __construct and __clone last week, and asked about how it might look. I 
wasn’t subscribed then so I didn’t see the earlier discussions.

I’ll go back and read through the earlier discussions, I don’t want to rehash 
what’s already been suggested and discarded due to impracticality.



> On 7 Sep 2016, at 19:04, Stephen Reay <php-li...@koalephant.com> wrote:
> 
> Right, but thats just because ($object) is a statement that evaluates to 
> $object and clone is a language construct, isn’t it? I don’t think I’ve ever 
> seen clone($object) used in the wild.
> 
> What do you think about having the change assignment(s) be handled by 
> __clone() (perhaps with a $changes array as its argument?), so the developer 
> still has control over how/what things are set, as they do in __construct.
> I fear that having the properties set by the clone operation is one step too 
> much into the ‘it happens by magic’ direction - PHP doesn't auto-set 
> properties passed to a constructor, so why here?
> 
> 
> 
>> On 7 Sep 2016, at 18:50, Silvio Marijić <marijic.sil...@gmail.com 
>> <mailto:marijic.sil...@gmail.com>> wrote:
>> 
>> Well it's not new, both clone $object and clone($object) are valid 
>> statements in PHP at the moment. But yes, you are close, in my opinion 
>> constructor and clone are the points where object can be modified.
>> Syntax can be discussed. But we should try to have minimal impact as 
>> possible on the syntax.
>> 
>> 2016-09-07 13:37 GMT+02:00 Stephen Reay <php-li...@koalephant.com 
>> <mailto:php-li...@koalephant.com>>:
>> OK. I could live with a concept where the object is only modifiable as part 
>> of the clone operation, but Im not mad about that syntax.
>> 
>> Are you proposing that clone($object, array $changes) is a new builtin 
>> function/language construct, and it does the actual property writes? In this 
>> situation, would it be safe to say that only the constructor (and 
>> destructor? e.g. imagine closing a resource handle in a destructor) can make 
>> changes to class properties?
>> 
>> Could that be achieved with syntax closer to what we use now? `clone $this 
>> use ($foo, $bar, $baz);` or similar?
>> 
>> 
>> 
>>> On 7 Sep 2016, at 18:19, Silvio Marijić <marijic.sil...@gmail.com 
>>> <mailto:marijic.sil...@gmail.com>> wrote:
>>> 
>>> I've forgot return in addItem() but you get the idea
>>> 
>>> 2016-09-07 13:19 GMT+02:00 Silvio Marijić <marijic.sil...@gmail.com 
>>> <mailto:marijic.sil...@gmail.com>>:
>>> Hi Stephen,
>>> 
>>> Well in your example it would look like this:
>>> 
>>> immutable class ValueObject {
>>>    public $values = [];
>>>    public function __construct($value) {
>>>       array_push($this->values, $value);
>>>    }
>>> 
>>> public function addItem($value){
>>>  $values = $this->values;
>>>  array_push($values, $value);
>>> 
>>>  $cloned = clone($this, ['values' => $values]
>>> }
>>> }
>>> 
>>> $vo = new ValueObject(1);
>>> $newVo = $vo->addItem(2);
>>> 
>>> 
>>> 
>>> On Sep 7, 2016 12:52 PM, "Stephen Reay" <php-li...@koalephant.com 
>>> <mailto:php-li...@koalephant.com>> wrote:
>>> Hi Silvio,
>>> 
>>> Can you give an example of what you mean about passing properties that are 
>>> changing?
>>> 
>>> Also, how would this affect e.g. an object that has objects or arrays as 
>>> members.
>>> 
>>> It’s not always going to be just `$clone = clone $this; $clone->foo = 
>>> $foo;` - you could be adding/appending/removing array/object members too.
>>> 
>>> Cheers
>>> 
>>> Stephen
>>> 
>>>> On 7 Sep 2016, at 17:43, Silvio Marijić <marijic.sil...@gmail.com 
>>>> <mailto:marijic.sil...@gmail.com>> wrote:
>>>> 
>>>> @Stephan
>>>> 
>>>> I am against that any kind of method can make modification on original 
>>>> object.
>>>> 
>>>> Cloning can be allowed but for this use case where you would pass 
>>>> properties that are changing, we would have to modify syntax of clone
>>>> 
>>>> On Sep 7, 2016 12:37 PM, "Stephen Reay" <php-li...@koalephant.com 
>>>> <mailto:php-li...@koalephant.com>> wrote:
>>>> Hey Matheiu, Silvio,
>>>> 
>>>> That is my main concern with the inability to clone from outside the 
>>>> class. I don’t think immutable should cause an error in this situation - 
>>>> if you really don’t want to allow users to create objects they can’t 
>>>> modify (which I understand) could clone on an immutable object from 
>>>> outside the class, simply return the object itself ?
>>>> 
>>>> Re: immutable only externally - yes, as I mentioned I can understand that 
>>>> would be a deal-break for some. In that situation, I’d be happy with some 
>>>> way to indicate that a method can make changes. Would this then mean that 
>>>> such a method could modify the object itself, rather than the clone?
>>>> 
>>>> Cheers
>>>> 
>>>> Stephen
>>>> 
>>>> > On 7 Sep 2016, at 17:09, Mathieu Rochette <math...@rochette.cc 
>>>> > <mailto:math...@rochette.cc>> wrote:
>>>> >
>>>> >
>>>> >
>>>> > On 07/09/2016 11:28, Silvio Marijić wrote:
>>>> >> Hi Stephen,
>>>> >>
>>>> >> Cloning is disabled at the moment in implementation because you would 
>>>> >> end
>>>> >> up with a object that you can not change, so you have no use of that. 
>>>> >> I'll
>>>> >> change that as soon as we find some good solution for handling that. 
>>>> >> Your
>>>> >> example is not really clear to me. At what point we should unlock/lock
>>>> >> object based on your example?
>>>> > what would happen if you tried to clone an immutable object, throw an 
>>>> > error ?
>>>> > it means that you might have to use reflection to check if the object is 
>>>> > immutable before cloning it. otherwise making a class immutable would be 
>>>> > a BC
>>>> >>
>>>> >> DateTimeImmutable does not prevent cloning because immutability is 
>>>> >> achieved
>>>> >> by encapsulation, and we want to get rid of the need of encapsulation in
>>>> >> our implementation of immutable objects.
>>>> >>
>>>> >> Best,
>>>> >> Silvio.
>>>> >>
>>>> >> 2016-09-07 11:05 GMT+02:00 Stephen Reay <php-li...@koalephant.com 
>>>> >> <mailto:php-li...@koalephant.com>>:
>>>> >>
>>>> >>> (Sorry for any dupes, sent from wrong address originally)
>>>> >>>
>>>> >>> From a developer point of view, I would suggest that a feature should 
>>>> >>> aim
>>>> >>> to be as clear to understand with as little “magic" as possible.
>>>> >>>
>>>> >>>
>>>> >>> If the goal of an immutable class is to allow public properties to be 
>>>> >>> made
>>>> >>> read-only, my expectation would be that:
>>>> >>>
>>>> >>> - write access to any public property from outside class context, is an
>>>> >>> error.
>>>> >>>
>>>> >>> This seems to be pretty much accepted by everyone
>>>> >>>
>>>> >>>
>>>> >>> - clone still works as expected
>>>> >>>
>>>> >>> There has been some suggestion that clone $immutableObj should not be
>>>> >>> allowed. Unless there is some specific language/engine gain by that, 
>>>> >>> what
>>>> >>> is the point of having this behaviour?
>>>> >>> Existing built-in immutable classes (like DateTimeImmutable) do not
>>>> >>> prevent cloning, so why should this?
>>>> >>>
>>>> >>> - regular cloning from within class method(s) is the suggested way to
>>>> >>> provide “create a copy of the object with a new value” functionality.
>>>> >>>
>>>> >>> This example was given before, effectively:
>>>> >>>
>>>> >>> public function withValue($val) {
>>>> >>>         $clone = clone $this;
>>>> >>>         $clone->val = $val;
>>>> >>>
>>>> >>>         return $clone;
>>>> >>> }
>>>> >>>
>>>> >>>
>>>> >>>
>>>> >>>
>>>> >>>
>>>> >>>> On 7 Sep 2016, at 13:57, Michał Brzuchalski <mic...@brzuchalski.com 
>>>> >>>> <mailto:mic...@brzuchalski.com>>
>>>> >>> wrote:
>>>> >>>> 06.09.2016 9:13 PM "Fleshgrinder" <p...@fleshgrinder.com 
>>>> >>>> <mailto:p...@fleshgrinder.com>> napisał(a):
>>>> >>>>> I understand the concerns of all of you very well and it's nice to 
>>>> >>>>> see a
>>>> >>>>> discussion around this topic. Fun fact, we are not the only ones with
>>>> >>>>> these issues: https://github.com/dotnet/roslyn/issues/159 
>>>> >>>>> <https://github.com/dotnet/roslyn/issues/159>
>>>> >>>>>
>>>> >>>>> On 9/6/2016 6:01 PM, Larry Garfield wrote:
>>>> >>>>>> How big of a need is it to allow returning $this instead of $clone,
>>>> >>>>>> and/or can that be internalized somehow as well?  With 
>>>> >>>>>> copy-on-write,
>>>> >>>>>> is that really an issue beyond a micro-optimization?
>>>> >>>>> I asked the same question before because I am also unable to answer 
>>>> >>>>> this
>>>> >>>>> question regarding the engine.
>>>> >>>>>
>>>> >>>>> However, for me it is more than micro-optimization, it is about
>>>> >>> identity.
>>>> >>>>> final class Immutable {
>>>> >>>>>   // ... the usual ...
>>>> >>>>>   public function withValue($value) {
>>>> >>>>>     $clone = clone $this;
>>>> >>>>>     $clone->value = $value;
>>>> >>>>>     return $clone;
>>>> >>>>>   }
>>>> >>>>> }
>>>> >>>>>
>>>> >>>>> $red = new Immutable('red');
>>>> >>>>> $still_red = $red->withValue('red');
>>>> >>>>>
>>>> >>>>> var_dump($red === $still_red); // bool(false)
>>>> >>>>>
>>>> >>>>> This is a problem in terms of value objects and PHP still does not 
>>>> >>>>> allow
>>>> >>>>> us operator overloading. A circumstance that I definitely want to
>>>> >>>>> address in the near future.
>>>> >>>>>
>>>> >>>>> But the keyword copy-on-write leads me to yet another proposal, 
>>>> >>>>> actually
>>>> >>>>> your input led me to two new proposals.
>>>> >>>>>
>>>> >>>>> # Copy-on-Write (CoW)
>>>> >>>>> Why are we even bothering on finding ways on making it hard for
>>>> >>>>> developers while the solution to our problem is directly in front of 
>>>> >>>>> us:
>>>> >>>>> PHP Strings!
>>>> >>>>>
>>>> >>>> AFAIK CoW in case of objects would be impossible to implement.
>>>> >>>>
>>>> >>>>> Every place in a PHP program refers to the same string if that 
>>>> >>>>> string is
>>>> >>>>> the same string. In the second someone mutates that string in any way
>>>> >>>>> she gets her own mutated reference to that string.
>>>> >>>>>
>>>> >>>>> That's exactly how we could deal with immutable objects. Developers 
>>>> >>>>> do
>>>> >>>>> not need to take care of anything, they just write totally normal
>>>> >>>>> objects and the engine takes care of everything.
>>>> >>>>>
>>>> >>>>> This approach also has the advantage that the return value of any 
>>>> >>>>> method
>>>> >>>>> is (as always) up to the developers.
>>>> >>>>>
>>>> >>>>> (Cloning is disabled and results in an error as is because it makes 
>>>> >>>>> no
>>>> >>>>> sense at all.)
>>>> >>>>>
>>>> >>>>> # Identity
>>>> >>>>> This directly leads to the second part of my thoughts and I already
>>>> >>>>> touched that topic: identity. If we have two strings their binary
>>>> >>>>> representation is always the same:
>>>> >>>>>
>>>> >>>>> var_dump('string' === 'string'); // bool(true)
>>>> >>>>>
>>>> >>>>> This is the exact behavior one wants for value objects too. Hence,
>>>> >>>>> immutable objects should have this behavior since they identify
>>>> >>>>> themselves by their values and not through instances. If I create two
>>>> >>>>> instances of Money with the amount 10 and the Currency EUR then they 
>>>> >>>>> are
>>>> >>>>> always the same, no matter what. This would also mean that no 
>>>> >>>>> developer
>>>> >>>>> ever needs to check if the new value is the same as the existing one,
>>>> >>>>> nor does anyone ever has to implement the flyweight pattern for
>>>> >>>>> immutable objects.
>>>> >>>>>
>>>> >>>>> A last very important attribute is that it does not matter in which
>>>> >>>>> thread an immutable value object is created because it always has the
>>>> >>>>> same identity regardless of it.
>>>> >>>>>
>>>> >>>>> This could easily be achieved by overwriting the object hashes
>>>> >>>>> (spl_object_hash) with something that hashes based on the values, and
>>>> >>>>> predictably across threads (UUIDs?).
>>>> >>>>>
>>>> >>>>> # Full Example
>>>> >>>>> <?php
>>>> >>>>>
>>>> >>>>> final immutable class ValueObject {
>>>> >>>>>
>>>> >>>>> public $value;
>>>> >>>>>
>>>> >>>>> public function __construct($value) {
>>>> >>>>>   $this->value = $value;
>>>> >>>>> }
>>>> >>>>>
>>>> >>>>> public function withValue($value) {
>>>> >>>>>   $this->value = $value;
>>>> >>>>> }
>>>> >>>>>
>>>> >>>>> }
>>>> >>>>>
>>>> >>>>> class A {
>>>> >>>>>
>>>> >>>>> public $vo;
>>>> >>>>>
>>>> >>>>> public function __construct(ValueObject $vo) {
>>>> >>>>>   $this->vo = $vo;
>>>> >>>>> }
>>>> >>>>>
>>>> >>>>> }
>>>> >>>>>
>>>> >>>>> class B {
>>>> >>>>>
>>>> >>>>> public $vo;
>>>> >>>>>
>>>> >>>>> public function __construct(ValueObject $vo) {
>>>> >>>>>   $this->vo = $vo;
>>>> >>>>> }
>>>> >>>>>
>>>> >>>>> }
>>>> >>>>>
>>>> >>>>> $vo = new ValueObject(1);
>>>> >>>>>
>>>> >>>>> $a = new A($vo);
>>>> >>>>> $b = new B($vo);
>>>> >>>>>
>>>> >>>>> var_dump($a->vo === $b->vo); // bool(true)
>>>> >>>>>
>>>> >>>>> $a->vo->withValue(2);
>>>> >>>>>
>>>> >>>>> var_dump($a->vo === $b->vo); // bool(false)
>>>> >>>>>
>>>> >>>>> $a->vo->withValue(1);
>>>> >>>>>
>>>> >>>>> var_dump($a->vo === $b->vo); // bool(true)
>>>> >>>>>
>>>> >>>>> // :)
>>>> >>>>>
>>>> >>>>> ?>
>>>> >>>>>
>>>> >>>>> --
>>>> >>>>> Richard "Fleshgrinder" Fussenegger
>>>> >>>>>
>>>> >>>
>>>> >>> --
>>>> >>> PHP Internals - PHP Runtime Development Mailing List
>>>> >>> To unsubscribe, visit: http://www.php.net/unsub.php 
>>>> >>> <http://www.php.net/unsub.php>
>>>> >>>
>>>> >>>
>>>> >>
>>>> >
>>>> 
>>> 
>>> 
>>> 
>>> 
>>> -- 
>>> Silvio Marijić
>>> Software Engineer
>>> 2e Systems
>> 
>> 
>> 
>> 
>> -- 
>> Silvio Marijić
>> Software Engineer
>> 2e Systems
> 

Reply via email to