And also Fleshgrinder made a good point about comparing two immutable
objects. They should be compared based on value, not on identity.

2016-09-07 11:28 GMT+02:00 Silvio Marijić <marijic.sil...@gmail.com>:

> 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?
>
> 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>:
>
>> (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>
>> wrote:
>> >
>> > 06.09.2016 9:13 PM "Fleshgrinder" <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
>> >>
>> >> 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
>>
>>
>
>
> --
> Silvio Marijić
> Software Engineer
> 2e Systems
>



-- 
Silvio Marijić
Software Engineer
2e Systems

Reply via email to