Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-02-04 Thread Larry Garfield
On Wed, Feb 3, 2021, at 8:14 AM, Nikita Popov wrote:
> On Mon, Dec 28, 2020 at 9:24 PM Larry Garfield 
> wrote:
> 
> > There's been a number of discussions of late around property visibility
> > and how to make objects more immutable.  Since it seems to have been
> > well-received in the past, I decided to do a complete analysis and context
> > of the various things that have been floated about recently.
> >
> > The full writeup is here:
> >
> > https://peakd.com/hive-168588/@crell/object-properties-and-immutability
> >
> > I hope it proves stimulating, at least of discussion and not naps.
> >
> 
> Thanks for the analysis Larry! I want to add a couple of thoughts from my
> side.
> 
> First of all, I think it's pretty clear that "asymmetric visibility" is the
> approach that gives us most of what we want for the least amount of effort.
> Asymmetric visibility has clear semantics, is (presumably) trivial to
> implement, and gives immutability guarantees that are "good enough" for
> most practical purposes. It's the pragmatic choice, and PHP is all about
> pragmatism...
> 
> That said, I don't think that asymmetric visibility is the correct solution
> to this problem space -- I don't think asymmetric visibility is ever (or
> only very rarely) what we actually want, it's just a good enough
> approximation. Unfortunately, the alternatives are more complex, and we
> have a limited budget on complexity.
> 
> Here are the pieces that I think would make up a proper solution to this
> space:
> 
> 1. initonly properties. This is in the sense of the previous "write once
> properties" proposal, though initonly is certainly the better name for the
> concept. Initonly properties represent complete immutability both inside
> and outside the class, and I do believe that this is the most common form
> of immutability needed (if it is needed at all).
> 
> Of course, as you correctly point out, initonly properties are incompatible
> with wither patterns that rely on clone-then-modify implementations. I
> think that ultimately, the "wither pattern" is an artifact of the fact that
> PHP only supports objects with by-handle semantics. The "wither pattern"
> emulates objects with by-value semantics, in a way that is verbose and
> inefficient.
> 
> I do want to point out that your presentation of copy-on-write when it
> comes to withers is not entirely correct: When you clone an object, this
> will always result in a full copy of the object, including all its
> properties. If you call a sequence of 5 wither methods, then this will
> create five objects and perform a copy of all properties every time. There
> is really no copy-on-write involved here, apart from the fact that property
> values (though not the property storage) can still be shared.
> 
> 2. This brings us to: Objects with by-value semantics. This was discussed
> in the thread, but I felt like it was dismissed a bit prematurely.
> 
> Ultimately, by-value semantics for objects is what withers are emulating.
> PSR-7 isn't "immutable", it's "mutable by-value". "Immutable + withers" is
> just a clumsy way to emulate that. If by-value objects were supported, then
> there would be no need for wither methods, and the "clone-then-modify"
> incompatibility of initonce properties would not be a problem in practice.
> You just write $request->method = 'POST' and this will either efficiently
> modify the request in-place (if you own it) or clone it and then modify it
> (if it is shared).
> 
> Another area where by-value objects are useful are data structures. PHP's
> by-value array type is probably one of those few instances where PHP got
> something right in a major way, that many other languages got wrong. But
> arrays have their own issues, in particular in how they try to service both
> lists and dictionaries at the same time, and fail where those intersect
> (dictionaries with integer keys or numeric string keys). People regularly
> suggest that we should be adding dedicated vector and dictionary objects,
> and one of the issues with that is that the resulting objects would follow
> the usual by-handle semantics, and would not serve as a mostly drop-in
> replacement for arrays. It is notable that while HHVM/Hack initially had
> vec and dict object types, they later created dedicated by-value types for
> these instead.
> 
> 3. Property accessors, or specifically for your PSR-7 examples, guards. The
> __clone related issues you're mostly dealing with in your examples are
> there because you need to replicate the validation logic in multiple
> places. If instead you could write something like
> 
> public string $method {
> guard($version) {
> if (!in_array($version, ['1.1', '1.0', '2.0'])) throw new
> InvalidArgumentException;
> }
> }
> 
> then this would ensure consistent enforcement of the property invariants
> regardless of how it is set.
> 
> Circling back, while I think that a combination of these features would be
> the "proper" 

Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-02-04 Thread Mike Schinkel
> On Feb 3, 2021, at 9:14 AM, Nikita Popov  wrote:
> 
> On Mon, Dec 28, 2020 at 9:24 PM Larry Garfield 
> wrote:
> 
>> There's been a number of discussions of late around property visibility
>> and how to make objects more immutable.  Since it seems to have been
>> well-received in the past, I decided to do a complete analysis and context
>> of the various things that have been floated about recently.
>> 
>> The full writeup is here:
>> 
>> https://peakd.com/hive-168588/@crell/object-properties-and-immutability
>> 
>> I hope it proves stimulating, at least of discussion and not naps.
>> 
> 
> Thanks for the analysis Larry! I want to add a couple of thoughts from my
> side.
> 
> First of all, I think it's pretty clear that "asymmetric visibility" is the
> approach that gives us most of what we want for the least amount of effort.
> Asymmetric visibility has clear semantics, is (presumably) trivial to
> implement, and gives immutability guarantees that are "good enough" for
> most practical purposes. It's the pragmatic choice, and PHP is all about
> pragmatism...
> 
> That said, I don't think that asymmetric visibility is the correct solution
> to this problem space -- I don't think asymmetric visibility is ever (or
> only very rarely) what we actually want, it's just a good enough
> approximation. Unfortunately, the alternatives are more complex, and we
> have a limited budget on complexity.
> 
> Here are the pieces that I think would make up a proper solution to this
> space:
> 
> 1. initonly properties. This is in the sense of the previous "write once
> properties" proposal, though initonly is certainly the better name for the
> concept. Initonly properties represent complete immutability both inside
> and outside the class, and I do believe that this is the most common form
> of immutability needed (if it is needed at all).
> 
> Of course, as you correctly point out, initonly properties are incompatible
> with wither patterns that rely on clone-then-modify implementations. I
> think that ultimately, the "wither pattern" is an artifact of the fact that
> PHP only supports objects with by-handle semantics. The "wither pattern"
> emulates objects with by-value semantics, in a way that is verbose and
> inefficient.
> 
> I do want to point out that your presentation of copy-on-write when it
> comes to withers is not entirely correct: When you clone an object, this
> will always result in a full copy of the object, including all its
> properties. If you call a sequence of 5 wither methods, then this will
> create five objects and perform a copy of all properties every time. There
> is really no copy-on-write involved here, apart from the fact that property
> values (though not the property storage) can still be shared.
> 
> 2. This brings us to: Objects with by-value semantics. This was discussed
> in the thread, but I felt like it was dismissed a bit prematurely.
> 
> Ultimately, by-value semantics for objects is what withers are emulating.
> PSR-7 isn't "immutable", it's "mutable by-value". "Immutable + withers" is
> just a clumsy way to emulate that. If by-value objects were supported, then
> there would be no need for wither methods, and the "clone-then-modify"
> incompatibility of initonce properties would not be a problem in practice.
> You just write $request->method = 'POST' and this will either efficiently
> modify the request in-place (if you own it) or clone it and then modify it
> (if it is shared).
> 
> Another area where by-value objects are useful are data structures. PHP's
> by-value array type is probably one of those few instances where PHP got
> something right in a major way, that many other languages got wrong. But
> arrays have their own issues, in particular in how they try to service both
> lists and dictionaries at the same time, and fail where those intersect
> (dictionaries with integer keys or numeric string keys). People regularly
> suggest that we should be adding dedicated vector and dictionary objects,
> and one of the issues with that is that the resulting objects would follow
> the usual by-handle semantics, and would not serve as a mostly drop-in
> replacement for arrays. It is notable that while HHVM/Hack initially had
> vec and dict object types, they later created dedicated by-value types for
> these instead.
> 
> 3. Property accessors, or specifically for your PSR-7 examples, guards. The
> __clone related issues you're mostly dealing with in your examples are
> there because you need to replicate the validation logic in multiple
> places. If instead you could write something like
> 
>public string $method {
>guard($version) {
>if (!in_array($version, ['1.1', '1.0', '2.0'])) throw new
> InvalidArgumentException;
>}
>}
> 
> then this would ensure consistent enforcement of the property invariants
> regardless of how it is set.
> 
> Circling back, while I think that a combination of these features would be
> the "proper" solution to the 

Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-02-03 Thread Pierre R.

Le 03/02/2021 à 15:14, Nikita Popov a écrit :


I've written up an initial draft for property accessors at
https://wiki.php.net/rfc/property_accessors, but once again I get the
distinct impression that this is adding a lot of language complexity, that
is possibly not justified (and it will be more complex once inheritance is
fully considered).

Overall, I'm still completely unsure what we should be doing :)

Regards,
Nikita


Hello,

I love pretty much everything of this draft, it will allow to write 
value types in a very concise manner.


Various notes thought:

 * Visibility modifier (public, protected, private) is useless and
   could be dropped entirely (I don't like var, but if that's necessary
   to keep it OK) for properties with asymmetric visibility directives,
   I don't know if the current parser will let you do that easily, but
   that would be a huge win for developers (even more concise code).
 * I love the fact that it can be combined with constructor promotion.
 * I love the guard and lazy features as proposed.

Regarding inheritance, obviously the most important point is that 
interface or class contracts should not be changed, so you may open for 
reading a closed property, but you may not close a readable property for 
example. This is true for writing as well of course. You're saying 
basically that a get'ed property would be passed by-value and thus it 
would forbid indirect access such as adding values to an array ? But 
what if the compiler could detect that get; is just get and not a 
function behind and compile opcodes as if it was a normal property (I 
don't know Zend internals at all, just guessing here) and considers that 
any other more complex getter to just be incompatible ? I guess that in 
languages such as C# that implement such asymmetric visibility 
mechanism, they always return object references, so this kind of problem 
just doesn't exist.


Thank you so much for this draft, I love the path it follows.

Regards,

--

Pierre



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-02-03 Thread Nikita Popov
On Mon, Dec 28, 2020 at 9:24 PM Larry Garfield 
wrote:

> There's been a number of discussions of late around property visibility
> and how to make objects more immutable.  Since it seems to have been
> well-received in the past, I decided to do a complete analysis and context
> of the various things that have been floated about recently.
>
> The full writeup is here:
>
> https://peakd.com/hive-168588/@crell/object-properties-and-immutability
>
> I hope it proves stimulating, at least of discussion and not naps.
>

Thanks for the analysis Larry! I want to add a couple of thoughts from my
side.

First of all, I think it's pretty clear that "asymmetric visibility" is the
approach that gives us most of what we want for the least amount of effort.
Asymmetric visibility has clear semantics, is (presumably) trivial to
implement, and gives immutability guarantees that are "good enough" for
most practical purposes. It's the pragmatic choice, and PHP is all about
pragmatism...

That said, I don't think that asymmetric visibility is the correct solution
to this problem space -- I don't think asymmetric visibility is ever (or
only very rarely) what we actually want, it's just a good enough
approximation. Unfortunately, the alternatives are more complex, and we
have a limited budget on complexity.

Here are the pieces that I think would make up a proper solution to this
space:

1. initonly properties. This is in the sense of the previous "write once
properties" proposal, though initonly is certainly the better name for the
concept. Initonly properties represent complete immutability both inside
and outside the class, and I do believe that this is the most common form
of immutability needed (if it is needed at all).

Of course, as you correctly point out, initonly properties are incompatible
with wither patterns that rely on clone-then-modify implementations. I
think that ultimately, the "wither pattern" is an artifact of the fact that
PHP only supports objects with by-handle semantics. The "wither pattern"
emulates objects with by-value semantics, in a way that is verbose and
inefficient.

I do want to point out that your presentation of copy-on-write when it
comes to withers is not entirely correct: When you clone an object, this
will always result in a full copy of the object, including all its
properties. If you call a sequence of 5 wither methods, then this will
create five objects and perform a copy of all properties every time. There
is really no copy-on-write involved here, apart from the fact that property
values (though not the property storage) can still be shared.

2. This brings us to: Objects with by-value semantics. This was discussed
in the thread, but I felt like it was dismissed a bit prematurely.

Ultimately, by-value semantics for objects is what withers are emulating.
PSR-7 isn't "immutable", it's "mutable by-value". "Immutable + withers" is
just a clumsy way to emulate that. If by-value objects were supported, then
there would be no need for wither methods, and the "clone-then-modify"
incompatibility of initonce properties would not be a problem in practice.
You just write $request->method = 'POST' and this will either efficiently
modify the request in-place (if you own it) or clone it and then modify it
(if it is shared).

Another area where by-value objects are useful are data structures. PHP's
by-value array type is probably one of those few instances where PHP got
something right in a major way, that many other languages got wrong. But
arrays have their own issues, in particular in how they try to service both
lists and dictionaries at the same time, and fail where those intersect
(dictionaries with integer keys or numeric string keys). People regularly
suggest that we should be adding dedicated vector and dictionary objects,
and one of the issues with that is that the resulting objects would follow
the usual by-handle semantics, and would not serve as a mostly drop-in
replacement for arrays. It is notable that while HHVM/Hack initially had
vec and dict object types, they later created dedicated by-value types for
these instead.

3. Property accessors, or specifically for your PSR-7 examples, guards. The
__clone related issues you're mostly dealing with in your examples are
there because you need to replicate the validation logic in multiple
places. If instead you could write something like

public string $method {
guard($version) {
if (!in_array($version, ['1.1', '1.0', '2.0'])) throw new
InvalidArgumentException;
}
}

then this would ensure consistent enforcement of the property invariants
regardless of how it is set.

Circling back, while I think that a combination of these features would be
the "proper" solution to the problem, they also add quite a bit of
complexity. Despite what I say above, I'm very much not convinced that
adding support for by-value objects is a good idea, due to the confusion
that two different object semantics could cause, 

Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-01-10 Thread Larry Garfield
On Sat, Jan 9, 2021, at 7:24 PM, G. P. B. wrote:
> On Sun, 10 Jan 2021 at 00:33, Larry Garfield  wrote:

> > It took a few days, but I am back with some more concrete examples.  I
> > decided to try and convert PSR-7 to the various options considered in my
> > previous post.  Here are the results:
> >
> > https://peakd.com/hive-168588/@crell/object-properties-part-2-examples
> >
> > Along with an analysis of the pros/cons of each.  As shown there,
> > `initonly` creates backdoors that make any but the most basic cases
> > untennable.
> >
> > --Larry Garfield
> >
> 
> Thanks for dwelling into this.
> 
> However, one can already have asymmetric visibility in PHP, just declare a
> __get() handler.
> Sure it is slow due to the VM -> User code -> VM jumps but it is possible.

Many things are technically possible, but only in lame ways.  The __get() 
callback is one such lame way of doing many things.  The existence of a lame 
workaround for something hasn't stopped us from improving the developer 
experience of the language before nor should it now.

> Moreover, asymmetric visibility does not prevent mutating an object by
> calling the constructor once again as follows:
> $obj->__construct(...$args);

I agree with Rowan's point here.  This is a bug in the language.  I've never 
actually seen that bug exploited in the wild, but the answer here is to fix 
that bug, not to use it as justification to not improve the language.

> This is IMHO the main reason why we want immutability/init only, not to
> reduce getter methods or wither methods, even if this makes some of them
> redundant.

The "main reason" for immutability depends on who you ask. :-)  My original 
post laid out some of the main arguments I've seen.  Which one is the "main 
reason" is subjective and I don't think there's any clear consensus on it.  
Fortunately, if we do it right we can all get what we want out of it and it 
doesn't matter which benefit was more important in hindsight.

> Also clone-with {} and clone "arguments" could very well be combined by
> having the props list being passed to the clone-with instruction as a
> $cloneContext array only available in __clone(), similar to how
> $http_response_header is populated. [1]
> The advantages I see in such a construct is that clone-with can handle any
> type concerns (single/union, enums, literals, typed arrays, generics
> if/when we get them) for the properties before passing them even to
> __clone().
> If no __clone() handler is defined then it can just assign them but if
> there needs to be one to handle extra validation, such as the type not
> being sufficient or a property being dependent on another you are already
> guaranteed that the property only needs minimal extra validation.

That would entail assigning the properties first, then allowing __clone() to 
override if desired, if I understand you correctly.  That means the object is 
in an invalid state at least for a time.  I'm not wild about that.  It would 
also change the logic of when __clone() happens, which right now is immediately 
after the object is duplicated.  What you're suggesting is changing it to:

* Duplicate object
* Assign with'ed properties
* Call __clone(), which could throw

To be fair, I didn't consider where the with'ed properties would be assigned 
relative to __clone() in my writeup.  (I should perhaps have done so.)

But that still doesn't resolve the issue of all the validation being shoved 
into one big method.  It only removes the "just assign it blindly" default 
case.  All of the other validation is still needed, and still just as fugly.

> As such I still believe immutability and asymmetric visibility are
> orthogonal features which might be related but fundamentally solve
> different problems.
> One is about data integrity, the other is about removing getters/setters.

Disagree.  Asymmetric visibility achieves nearly all the same end results as 
initonly, but without introducing data integrity problems or fugly hacks 
(__clone()) to resolve them.  The main takeaway from my experimentation, as I 
see it, is that initonly offers very little *in practice* in the way of data 
integrity guarantees beyond what asymmetric visibility does.  Only in the 
trivial case where a property is fully validated by the type system 
automatically and has no inter-dependencies does it have any benefit.  And the 
benefit is, actually, only moving the `clone with` statement from inside a 
single-expression method (which I'm hoping to make simpler, as noted) to the 
calling code.  I'm not sure that's always a net win.

--Larry Garfield

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-01-10 Thread Rowan Tommins
On 10 January 2021 01:24:38 GMT+00:00, "G. P. B."  
wrote:
>Moreover, asymmetric visibility does not prevent mutating an object by
>calling the constructor once again as follows:
>$obj->__construct(...$args);


That's pretty trivial to work around: mark the constructor private and provide 
one or more public static methods that call it. That's actually a pretty common 
and useful design in its own right.

It's also something that could probably be banned at the language level. I seem 
to remember it being discussed before, but the details aren't quite trivial 
because you need to allow parent::__construct etc. I'd rather spend the time to 
work out those details than design the rest of the language around it being 
possible, if it's really that much of an issue.

Regards,

-- 
Rowan Tommins
[IMSoP]

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-01-09 Thread G. P. B.
On Sun, 10 Jan 2021 at 00:33, Larry Garfield  wrote:

> On Sun, Jan 3, 2021, at 11:29 AM, Olle Härstedt wrote:
>
> > > I'll disagree slightly.  A language feature should introduce more
> power than
> > > it does complexity.  Not everything *can* be made absolutely simple,
> but the
> > > power it offers is worth it.  I'd say it should minimize introduced
> > > complexity, relative to the power offered.  Complexity ideally is
> super low,
> > > but it's never zero simply by virtue of being "one more thing" that
> > > developers need to know how to read.
> > >
> > > So in this case, we need to compare the power/complexity of asymmetric
> > > visibility vs the power/complexity of "immutable... except in these
> > > situations."  I would argue that asymmetric visibility is more
> > > self-documenting, because it states explicitly what those situations
> are.
> > >
> > > The other point is that, as noted, "initonly" creates a gap if you have
> > > properties that are inter-dependent.  Those then cannot be made
> public-read,
> > > because that would also mean public-clone-with, and thus allow callers
> to
> > > violate property relationships.  Asymmetric visibility does not have
> that
> > > problem.
> >
> > Can you perhaps be a bit more clear on why initonly/readonly would be
> > a deal breaker? Seems to me like readonly would cover 80% of
> > use-cases? Which is to make data-value objects humane (and fast, since
> > you don't need getters anymore) to work with. Seems like you're
> > focusing too much on an edge case here. Maybe we should list the
> > possibly use-cases? Or at least the main target use-case.
> >
> > If an object has invariants that need to hold, just throw an exception
> > in __clone to force use with withX() instead? Or, as you suggested,
> > improve __clone by giving it arguments?
> >
> > Olle
>
> It took a few days, but I am back with some more concrete examples.  I
> decided to try and convert PSR-7 to the various options considered in my
> previous post.  Here are the results:
>
> https://peakd.com/hive-168588/@crell/object-properties-part-2-examples
>
> Along with an analysis of the pros/cons of each.  As shown there,
> `initonly` creates backdoors that make any but the most basic cases
> untennable.
>
> --Larry Garfield
>

Thanks for dwelling into this.

However, one can already have asymmetric visibility in PHP, just declare a
__get() handler.
Sure it is slow due to the VM -> User code -> VM jumps but it is possible.

Moreover, asymmetric visibility does not prevent mutating an object by
calling the constructor once again as follows:
$obj->__construct(...$args);

This is IMHO the main reason why we want immutability/init only, not to
reduce getter methods or wither methods, even if this makes some of them
redundant.

Also clone-with {} and clone "arguments" could very well be combined by
having the props list being passed to the clone-with instruction as a
$cloneContext array only available in __clone(), similar to how
$http_response_header is populated. [1]
The advantages I see in such a construct is that clone-with can handle any
type concerns (single/union, enums, literals, typed arrays, generics
if/when we get them) for the properties before passing them even to
__clone().
If no __clone() handler is defined then it can just assign them but if
there needs to be one to handle extra validation, such as the type not
being sufficient or a property being dependent on another you are already
guaranteed that the property only needs minimal extra validation.

As such I still believe immutability and asymmetric visibility are
orthogonal features which might be related but fundamentally solve
different problems.
One is about data integrity, the other is about removing getters/setters.

Best regards,

George P. Banyard

[1] https://www.php.net/manual/en/reserved.variables.httpresponseheader.php


Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-01-09 Thread Larry Garfield
On Sun, Jan 3, 2021, at 11:29 AM, Olle Härstedt wrote:

> > I'll disagree slightly.  A language feature should introduce more power than
> > it does complexity.  Not everything *can* be made absolutely simple, but the
> > power it offers is worth it.  I'd say it should minimize introduced
> > complexity, relative to the power offered.  Complexity ideally is super low,
> > but it's never zero simply by virtue of being "one more thing" that
> > developers need to know how to read.
> >
> > So in this case, we need to compare the power/complexity of asymmetric
> > visibility vs the power/complexity of "immutable... except in these
> > situations."  I would argue that asymmetric visibility is more
> > self-documenting, because it states explicitly what those situations are.
> >
> > The other point is that, as noted, "initonly" creates a gap if you have
> > properties that are inter-dependent.  Those then cannot be made public-read,
> > because that would also mean public-clone-with, and thus allow callers to
> > violate property relationships.  Asymmetric visibility does not have that
> > problem.
> 
> Can you perhaps be a bit more clear on why initonly/readonly would be
> a deal breaker? Seems to me like readonly would cover 80% of
> use-cases? Which is to make data-value objects humane (and fast, since
> you don't need getters anymore) to work with. Seems like you're
> focusing too much on an edge case here. Maybe we should list the
> possibly use-cases? Or at least the main target use-case.
> 
> If an object has invariants that need to hold, just throw an exception
> in __clone to force use with withX() instead? Or, as you suggested,
> improve __clone by giving it arguments?
> 
> Olle

It took a few days, but I am back with some more concrete examples.  I decided 
to try and convert PSR-7 to the various options considered in my previous post. 
 Here are the results:

https://peakd.com/hive-168588/@crell/object-properties-part-2-examples

Along with an analysis of the pros/cons of each.  As shown there, `initonly` 
creates backdoors that make any but the most basic cases untennable.

--Larry Garfield

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-01-03 Thread Olle Härstedt
2021-01-03 16:55 GMT, Larry Garfield :
> On Sun, Jan 3, 2021, at 8:28 AM, Olle Härstedt wrote:
>
>> >> I like that you connect higher level design patterns with language
>> >> design. This is the way to go, IMO. Personally, I'd prefer support for
>> >> the Psalm notation `@psalm-readonly`, which is the same as your
>> >> initonly. Clone-with makes sense too, as this construct is already
>> >> supported in multiple languages. The exact notation doesn't matter
>> >> that much - my personal choice is OCaml {record with x = 10} over JS
>> >> spread operator, but OCaml is pretty "wordy" in notation in contrast
>> >> to the C tradition that PHP is part of.
>> >>
>> >> Reintroducing "objects that pass by value" is a hard pass from me. The
>> >> way forward is immutability and constrained mutability (ownership,
>> >> escape analysis, etc). Psalm also supports array shapes - maybe this
>> >> can be investigated as an alternative? Since PHP has no tuples.
>> >>
>> >> I'm not convinced the added complexity of asymmetric visibility is
>> >> powerful enough to motivate its existence. Feel free to prove me
>> >> wrong. :) My choice here would be namespace "internal" (also supported
>> >> by Psalm already), but this requires implementation of namespace
>> >> visibility, a PR that was abandoned.
>> >>
>> >> And also, happy new year!
>> >
>> > Happy New Year!
>> >
>> > I agree that "objects, but passing by value" would not be the right
>> > solution. I used to think that would be a good part of the solution,
>> > but
>> > eventually concluded that it would introduce more complexity, not less.
>> > Eventually, everything people wanted to do with objects they'd want to
>> > do
>> > with "Records" (for lack of a better term), and if they pass by value
>> > but
>> > are still mutable then you have a weird situation where sometimes
>> > changes
>> > propagate and some don't (depending on if you have a record or object).
>> > Making it easier to use objects in a value-esque way will get us closer
>> > to
>> > the desired end state.
>> >
>> > I think the tldr of my post is this: A single "immutable" flag
>> > (whatever
>> > it's called) on a class or property would require having lots of holes
>> > poked
>> > in it in order to make it useful in practice (mostly what "initonly"
>> > would
>> > do), but those holes would introduce other holes we don't want (cloning
>> > an
>> > object from the outside when you shouldn't).
>>
>> I new language feature needs to be both simple and powerful - it's not
>> enough to be only powerful. A second problem I see is how asymmetric
>> visibility would affect the readability of a class, putting extra
>> strain in understanding it. Thirdly, how does PHP differ from FP
>> languages like OCaml and Haskell in this regard, neither who uses
>> visibility in this way? What's acceptable in those languages that
>> would be unacceptable in PHP?
>>
>> Olle
>
> I'll disagree slightly.  A language feature should introduce more power than
> it does complexity.  Not everything *can* be made absolutely simple, but the
> power it offers is worth it.  I'd say it should minimize introduced
> complexity, relative to the power offered.  Complexity ideally is super low,
> but it's never zero simply by virtue of being "one more thing" that
> developers need to know how to read.
>
> So in this case, we need to compare the power/complexity of asymmetric
> visibility vs the power/complexity of "immutable... except in these
> situations."  I would argue that asymmetric visibility is more
> self-documenting, because it states explicitly what those situations are.
>
> The other point is that, as noted, "initonly" creates a gap if you have
> properties that are inter-dependent.  Those then cannot be made public-read,
> because that would also mean public-clone-with, and thus allow callers to
> violate property relationships.  Asymmetric visibility does not have that
> problem.

Can you perhaps be a bit more clear on why initonly/readonly would be
a deal breaker? Seems to me like readonly would cover 80% of
use-cases? Which is to make data-value objects humane (and fast, since
you don't need getters anymore) to work with. Seems like you're
focusing too much on an edge case here. Maybe we should list the
possibly use-cases? Or at least the main target use-case.

If an object has invariants that need to hold, just throw an exception
in __clone to force use with withX() instead? Or, as you suggested,
improve __clone by giving it arguments?

Olle

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-01-03 Thread Larry Garfield
On Sun, Jan 3, 2021, at 8:28 AM, Olle Härstedt wrote:

> >> I like that you connect higher level design patterns with language
> >> design. This is the way to go, IMO. Personally, I'd prefer support for
> >> the Psalm notation `@psalm-readonly`, which is the same as your
> >> initonly. Clone-with makes sense too, as this construct is already
> >> supported in multiple languages. The exact notation doesn't matter
> >> that much - my personal choice is OCaml {record with x = 10} over JS
> >> spread operator, but OCaml is pretty "wordy" in notation in contrast
> >> to the C tradition that PHP is part of.
> >>
> >> Reintroducing "objects that pass by value" is a hard pass from me. The
> >> way forward is immutability and constrained mutability (ownership,
> >> escape analysis, etc). Psalm also supports array shapes - maybe this
> >> can be investigated as an alternative? Since PHP has no tuples.
> >>
> >> I'm not convinced the added complexity of asymmetric visibility is
> >> powerful enough to motivate its existence. Feel free to prove me
> >> wrong. :) My choice here would be namespace "internal" (also supported
> >> by Psalm already), but this requires implementation of namespace
> >> visibility, a PR that was abandoned.
> >>
> >> And also, happy new year!
> >
> > Happy New Year!
> >
> > I agree that "objects, but passing by value" would not be the right
> > solution. I used to think that would be a good part of the solution, but
> > eventually concluded that it would introduce more complexity, not less.
> > Eventually, everything people wanted to do with objects they'd want to do
> > with "Records" (for lack of a better term), and if they pass by value but
> > are still mutable then you have a weird situation where sometimes changes
> > propagate and some don't (depending on if you have a record or object).
> > Making it easier to use objects in a value-esque way will get us closer to
> > the desired end state.
> >
> > I think the tldr of my post is this: A single "immutable" flag (whatever
> > it's called) on a class or property would require having lots of holes poked
> > in it in order to make it useful in practice (mostly what "initonly" would
> > do), but those holes would introduce other holes we don't want (cloning an
> > object from the outside when you shouldn't).
> 
> I new language feature needs to be both simple and powerful - it's not
> enough to be only powerful. A second problem I see is how asymmetric
> visibility would affect the readability of a class, putting extra
> strain in understanding it. Thirdly, how does PHP differ from FP
> languages like OCaml and Haskell in this regard, neither who uses
> visibility in this way? What's acceptable in those languages that
> would be unacceptable in PHP?
> 
> Olle

I'll disagree slightly.  A language feature should introduce more power than it 
does complexity.  Not everything *can* be made absolutely simple, but the power 
it offers is worth it.  I'd say it should minimize introduced complexity, 
relative to the power offered.  Complexity ideally is super low, but it's never 
zero simply by virtue of being "one more thing" that developers need to know 
how to read.

So in this case, we need to compare the power/complexity of asymmetric 
visibility vs the power/complexity of "immutable... except in these 
situations."  I would argue that asymmetric visibility is more 
self-documenting, because it states explicitly what those situations are.

The other point is that, as noted, "initonly" creates a gap if you have 
properties that are inter-dependent.  Those then cannot be made public-read, 
because that would also mean public-clone-with, and thus allow callers to 
violate property relationships.  Asymmetric visibility does not have that 
problem.

As far as other language comparisons, I've never written in OCaml and can only 
barely read Haskell. :-)  However, the relevant points as I understand them are:

* In strictly functional languages (Haskell, etc.), immutability is assumed by 
default.  So the rest of the syntax, runtime behavior, and community standards 
are built on that assumption.  That's not true in PHP.

* Haskell at least (and I presume other strictly functional languages, although 
I've not dug into them in any detail at all) know you're going to be calling a 
bazillion functions, often recursively, and so the engine can reorder things, 
execute lazily, skip having a stack entirely, or do other things to make a 
deeply recursive function design highly performant.  That's not the case in 
PHP, so usually an iterative algorithm is going to be more performant but 
requires mutating variables.  So the engine is optimized for that by default.

Compare the idealized functional/immutable fibbonaci with its mutable-iterative 
version:

function fp_fib(int $n) {
  return match($n) {
0, 1 => 1,
 default => fp_fib(n-1) - fp_fib(n-2),
  };
}

function fibonacci_iterative(int $n)
{
$previous = 1;
$current = 1;
$next = 1;
   

Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-01-03 Thread Olle Härstedt
2021-01-02 16:06 GMT, Larry Garfield :
> On Fri, Jan 1, 2021, at 5:51 PM, Olle Härstedt wrote:
>
>> >> The web dev discourse is
>> >> one-sided with regard to immutability,
>> >
>> > Yes, if you've heard any of the regular whining about PSR-7 being an
>> > immutable object you'd think it's one-sided in favor of mutability. ;-)
>> >
>> > As you say, the point here is to add tools.  Right now, doing
>> > immutability
>> > in PHP in syntactically clumsy and ugly.  We want to fix that, and that
>> > has
>> > to include some means of "give me a new value based on this existing
>> > value
>> > but with some difference."  (aka, exactly what with-er methods do,
>> > although
>> > I agree entirely that if you have the option of less generic names, use
>> > them).
>> >
>> > So, can we get back to the original post, which is proposing specifics
>> > of
>> > the tools to make that happen? :-)  (Asymmetric visibility and
>> > clone-with,
>> > specifically.)
>> >
>>
>> OK!
>>
>> I like that you connect higher level design patterns with language
>> design. This is the way to go, IMO. Personally, I'd prefer support for
>> the Psalm notation `@psalm-readonly`, which is the same as your
>> initonly. Clone-with makes sense too, as this construct is already
>> supported in multiple languages. The exact notation doesn't matter
>> that much - my personal choice is OCaml {record with x = 10} over JS
>> spread operator, but OCaml is pretty "wordy" in notation in contrast
>> to the C tradition that PHP is part of.
>>
>> Reintroducing "objects that pass by value" is a hard pass from me. The
>> way forward is immutability and constrained mutability (ownership,
>> escape analysis, etc). Psalm also supports array shapes - maybe this
>> can be investigated as an alternative? Since PHP has no tuples.
>>
>> I'm not convinced the added complexity of asymmetric visibility is
>> powerful enough to motivate its existence. Feel free to prove me
>> wrong. :) My choice here would be namespace "internal" (also supported
>> by Psalm already), but this requires implementation of namespace
>> visibility, a PR that was abandoned.
>>
>> And also, happy new year!
>
> Happy New Year!
>
> I agree that "objects, but passing by value" would not be the right
> solution. I used to think that would be a good part of the solution, but
> eventually concluded that it would introduce more complexity, not less.
> Eventually, everything people wanted to do with objects they'd want to do
> with "Records" (for lack of a better term), and if they pass by value but
> are still mutable then you have a weird situation where sometimes changes
> propagate and some don't (depending on if you have a record or object).
> Making it easier to use objects in a value-esque way will get us closer to
> the desired end state.
>
> I think the tldr of my post is this: A single "immutable" flag (whatever
> it's called) on a class or property would require having lots of holes poked
> in it in order to make it useful in practice (mostly what "initonly" would
> do), but those holes would introduce other holes we don't want (cloning an
> object from the outside when you shouldn't).

I new language feature needs to be both simple and powerful - it's not
enough to be only powerful. A second problem I see is how asymmetric
visibility would affect the readability of a class, putting extra
strain in understanding it. Thirdly, how does PHP differ from FP
languages like OCaml and Haskell in this regard, neither who uses
visibility in this way? What's acceptable in those languages that
would be unacceptable in PHP?

Olle

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-01-03 Thread Rowan Tommins
On 2 January 2021 21:25:08 GMT+00:00, Larry Garfield  
wrote:
>If a stream is not seekable, then it would have to consume and destroy
>$fp in the process (unset it).  So:
>
>[$line1, $fp2] = read_line($fp);
>[$line2, $fp2] = read_line($fp);
>
>The second line would throw an error that $fp "has been consumed" or
>something like that.  But even that still creates potential for
>spooky-action-at-a-distance if $fp was passed into a function, gets
>read in that function, and then the parent call scope has a broken $fp
>lying around.


Yes, that is where "uniqueness attributes" come in: in Clean, that's basically 
how I/O looks, but either of those scenarios would produce an error *at compile 
time*. The type system includes the constraint that the file handle must not be 
reachable from anywhere else when passed to the read_line function, whether 
that's use of the same variable after the call, assignment to an extra 
variable, capture by some other function, or storage in an array or record.

The same constraint can be added to custom functions, allowing the compiler to 
reuse the memory for, say, a large array that you're adding an item to. So you 
still write the code as though it was immutable, and can reason about it that 
way, but can also prove that it's safe to actually mutate it in place.

Similar things can be done, in a slightly different way, with Rust's 
ownership/lifetime system: the "borrow checker" proves that the manipulations 
you're doing are free of "action at a distance" by prohibiting anything that 
would create ambiguous "ownership".


Regards,

-- 
Rowan Tommins
[IMSoP]

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-01-02 Thread Paul M. Jones
Hi Rowan and all,

I apologize in advance for the wall-of-text; the short questions lead to long 
answers.


> On Jan 2, 2021, at 12:56, Rowan Tommins  wrote:
> 
> On 01/01/2021 20:31, Paul M. Jones wrote:
> 
>> The complaints against the incomplete and inconsistent immutability of PSR-7 
>> have merit.
> 
> The big mistake of PSR-7, in my view, is mixing immutable objects with 
> streams, which are inherently mutable/stateful.

(/me nods along)

Streams were noted as the one explicit exception to immutability in PSR-7. 
Looking back on it, that should have been a sign to us that immutability should 
not have been a goal.

(Re: PSR-7 but not re: immutability, there is at least one more mistake born of 
the original intent, that seemed reasonable at the time but in hindsight was 
another poor decision: it combines the concerns of the HTTP message with the 
concerns of middleware communication. This observation is attributable to 
[deleted] at Reddit ...

  
https://www.reddit.com/r/PHP/comments/5ojqr0/q_how_many_psr7_implementations_exist_a_zero/dcjxtxl/

... stating "[T]he true intent of PSR-7 [is] not to be an HTTP message 
standard, but to be middleware IO standard, which happens to be mostly (but not 
only) an HTTP message." It's an accurate assessment.)


> I wonder if there are any lessons to be learned there in terms of what kinds 
> of immutability the language should encourage / make easy.

I think there are; I wrote about at least some of them here ...

  
https://paul-m-jones.com/post/2016/09/06/avoiding-quasi-immutable-objects-in-php/

... in which I conclude that, if you want to build a truly immutable object in 
PHP, it appears the best approach is the following:

- Default to using only scalars and nulls as properties.

- Avoid streams as properties; if a property must be a stream, make sure that 
it is read-only, and that its state is restored each time it is used.

- Avoid objects as properties; if a property must be an object, make sure that 
object is itself immutable.

- Especially avoid arrays as properties; use only with extreme caution and care.

- Implement __set() to disallow setting of undefined properties.

- Possibly implement __unset() to warn that the object is immutable.

I put those conclusions (and other resulting from that article) into an 
implementation described here:

  http://paul-m-jones.com/post/2019/02/04/immutability-package-for-php/


> is it better to constrain entire objects to be immutable rather than 
> individual properties?

I would say that the entire object ought to be immutable, for reasons that are 
difficult for me to articulate.


> And should there be restrictions on what you can declare as immutable, since 
> "immutable resource" is largely nonsensical?


I think so, and I note some of those restrictions above. In particular, the 
immutability package ValueObject further inspects arrays to restrict their 
values to immutables as well.


-- 
Paul M. Jones
pmjo...@pmjones.io
http://paul-m-jones.com

Modernizing Legacy Applications in PHP
https://leanpub.com/mlaphp

Solving the N+1 Problem in PHP
https://leanpub.com/sn1php

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-01-02 Thread Olle Härstedt
2021-01-02 21:25 GMT, Larry Garfield :
> On Sat, Jan 2, 2021, at 12:56 PM, Rowan Tommins wrote:
>> On 01/01/2021 20:31, Paul M. Jones wrote:
>> > The complaints against the incomplete and inconsistent immutability of
>> > PSR-7 have merit.
>>
>>
>> The big mistake of PSR-7, in my view, is mixing immutable objects with
>> streams, which are inherently mutable/stateful. I wonder if there are
>> any lessons to be learned there in terms of what kinds of immutability
>> the language should encourage / make easy.
>>
>> For instance, is it better to constrain entire objects to be immutable
>> rather than individual properties? And should there be restrictions on
>> what you can declare as immutable, since "immutable resource" is largely
>> nonsensical?
>>
>> Or is it rather a reflection that building purely immutable
>> implementations is hard, and the language needs other facilities
>> (monads? ownership?) to mix in those parts that don't fit?
>>
>> Regards,
>
> I rarely hear that called out as a PSR-7 complaint specifically, in
> practice, but moving on...
>
> IMO, it's better to put the focus on immutable properties.  There are use
> cases where you want only some properties to be immutable, but not the whole
> class.  If you do want the whole class, then marking all the properties
> immutable is effectively the same thing.
>
> Though, again, in practice, at least in PHP, I don't think immutable
> properties should be the goal.  Asymmetric visibility lets us built safely
> immutable-from-the-outside objects that are "up to you" on the inside.  I
> think that gives us a better end result given the nature of PHP.  In other
> languages that wouldn't make as much sense, but PHP is what it is.
>
> Copy on write makes "immutable data structures" not something we need to
> build explicitly; we get "close enough" for free.  If you really wanted to
> micro-optimize the memory and CPU usage further than that... go build it in
> Rust instead.

Correct me if I'm wrong, but copy-on-write is only beneficial with
values, not references to values (objects)? When you clone with a
`with` method, you always write, so you always have to copy. And
objects are already free to pass around without any copying happening
automatically (as is the case with arrays, which have value semantics,
which is why copy-on-write was implemented to not copy needlessly when
an array is only read from).

Olle

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-01-02 Thread Larry Garfield
On Sat, Jan 2, 2021, at 12:56 PM, Rowan Tommins wrote:
> On 01/01/2021 20:31, Paul M. Jones wrote:
> > The complaints against the incomplete and inconsistent immutability of 
> > PSR-7 have merit.
> 
> 
> The big mistake of PSR-7, in my view, is mixing immutable objects with 
> streams, which are inherently mutable/stateful. I wonder if there are 
> any lessons to be learned there in terms of what kinds of immutability 
> the language should encourage / make easy.
> 
> For instance, is it better to constrain entire objects to be immutable 
> rather than individual properties? And should there be restrictions on 
> what you can declare as immutable, since "immutable resource" is largely 
> nonsensical?
> 
> Or is it rather a reflection that building purely immutable 
> implementations is hard, and the language needs other facilities 
> (monads? ownership?) to mix in those parts that don't fit?
> 
> Regards,

I rarely hear that called out as a PSR-7 complaint specifically, in practice, 
but moving on...

IMO, it's better to put the focus on immutable properties.  There are use cases 
where you want only some properties to be immutable, but not the whole class.  
If you do want the whole class, then marking all the properties immutable is 
effectively the same thing.

Though, again, in practice, at least in PHP, I don't think immutable properties 
should be the goal.  Asymmetric visibility lets us built safely 
immutable-from-the-outside objects that are "up to you" on the inside.  I think 
that gives us a better end result given the nature of PHP.  In other languages 
that wouldn't make as much sense, but PHP is what it is.

Copy on write makes "immutable data structures" not something we need to build 
explicitly; we get "close enough" for free.  If you really wanted to 
micro-optimize the memory and CPU usage further than that... go build it in 
Rust instead.

Wrapping immutable behavior around IO is... ugly, gross, and disgusting. :-)  
Even supposedly Twue Pure languages like Haskell don't actually do that; it 
just hides the IO mutability in the engine and whistles innocently while 
muttering "monad" under its breath. :-)

At least in the abstract, immutability and IO would require IO primitives that 
returned both a read value and a new stream pointer, possibly consuming and 
destroying the old one.  If a stream is seekable, you could conceptually do 
something like:

$fp = file_open('foo.txt');
[$line, $fp2] = read_line($fp);

In which $fp2 and $fp refer to the same file stream on disk, but their stream 
pointers are different.  In practice you'd likely use $fp as the second 
parameter and lose the old reference, which is good enough.  That's a bit 
clumsy, though, and where one might use something monad-based to make the code 
a bit simpler.  I don't know off hand what that would look like, though.

[$line1, $fp2] = read_line($fp);
[$line2, $fp2] = read_line($fp);
[$line3, $fp2] = read_line($fp);
[$line4, $fp2] = read_line($fp);

In the above example, since $fp is never overwritten, all 4 $line variables are 
the same thing.

If a stream is not seekable, then it would have to consume and destroy $fp in 
the process (unset it).  So:

[$line1, $fp2] = read_line($fp);
[$line2, $fp2] = read_line($fp);

The second line would throw an error that $fp "has been consumed" or something 
like that.  But even that still creates potential for 
spooky-action-at-a-distance if $fp was passed into a function, gets read in 
that function, and then the parent call scope has a broken $fp lying around.

IO is inherently impure and mutable, and always will be.  I don't think it's 
realistic for us to fix that, certainly not in PHP.  Instead we should be 
making it easy to encapsulate the IO into safe corners where you can guard it 
carefully and keep everything else as pure as reasonable.

All of which is why the scope I'm looking at is not how to make PHP 
Haskell-esque pure.  It's how do we make it more ergonomic for developers to 
build stateless code in those places where it's reasonable to do so.  It's a 
much less ambitious, but therefore more achievable, scope.

--Larry Garfield

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-01-02 Thread Rowan Tommins

On 01/01/2021 20:31, Paul M. Jones wrote:

The complaints against the incomplete and inconsistent immutability of PSR-7 
have merit.



The big mistake of PSR-7, in my view, is mixing immutable objects with 
streams, which are inherently mutable/stateful. I wonder if there are 
any lessons to be learned there in terms of what kinds of immutability 
the language should encourage / make easy.


For instance, is it better to constrain entire objects to be immutable 
rather than individual properties? And should there be restrictions on 
what you can declare as immutable, since "immutable resource" is largely 
nonsensical?


Or is it rather a reflection that building purely immutable 
implementations is hard, and the language needs other facilities 
(monads? ownership?) to mix in those parts that don't fit?


Regards,

--
Rowan Tommins
[IMSoP]

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-01-02 Thread Rowan Tommins

On 31/12/2020 14:04, Olle Härstedt wrote:

Yes, of course you can find use-cases where immutability is a better
choice, just like I can find use-cases where (constrained) mutability
is better. The point is not to replace one tool with another, but
rather adding another tool to the toolbox. The web dev discourse is
one-sided with regard to immutability, I think. Wish I had time to
implement a PR to Psalm to show something more concrete... Again, if
you only have a hammer, everything looks like a nail. :)



Certainly, I didn't mean to say that immutability was always the perfect 
choice. I think it's popular because it's an easy hammer to borrow from 
the fashionable Functional Programming toolbox - you can get a lot of 
its advantages without much support from the language, and it genuinely 
fits a lot of use cases encountered in high-level programming.


Where ownership concepts seem to shine is where immutability is either 
impossible (e.g. consuming from a network stream or an event queue) or 
otherwise undesirable (e.g. working with large amounts of data, or 
tightly optimised code).


I read a bit about Uniqueness Attributes in Clean [1] and it seems they 
are implemented there so that the *user* can treat everything as 
immutable, but the *compiler* can safely mutate underlying structures. 
So in that implementation at least, a "mutable record" would in fact be 
implemented with the equivalent of "clone ... with", so that it appeared 
*from the outside* to return a new instance each time.


It's certainly an interesting concept, particularly for the I/O case 
(where immutability is genuinely not an option) but how easy it would be 
to retro-fit to a dynamic language like PHP I'm not sure.


[1] https://cloogle.org/doc/#_9


Regards,

--
Rowan Tommins
[IMSoP]

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-01-02 Thread Larry Garfield
On Fri, Jan 1, 2021, at 5:51 PM, Olle Härstedt wrote:

> >> The web dev discourse is
> >> one-sided with regard to immutability,
> >
> > Yes, if you've heard any of the regular whining about PSR-7 being an
> > immutable object you'd think it's one-sided in favor of mutability. ;-)
> >
> > As you say, the point here is to add tools.  Right now, doing immutability
> > in PHP in syntactically clumsy and ugly.  We want to fix that, and that has
> > to include some means of "give me a new value based on this existing value
> > but with some difference."  (aka, exactly what with-er methods do, although
> > I agree entirely that if you have the option of less generic names, use
> > them).
> >
> > So, can we get back to the original post, which is proposing specifics of
> > the tools to make that happen? :-)  (Asymmetric visibility and clone-with,
> > specifically.)
> >
> 
> OK!
> 
> I like that you connect higher level design patterns with language
> design. This is the way to go, IMO. Personally, I'd prefer support for
> the Psalm notation `@psalm-readonly`, which is the same as your
> initonly. Clone-with makes sense too, as this construct is already
> supported in multiple languages. The exact notation doesn't matter
> that much - my personal choice is OCaml {record with x = 10} over JS
> spread operator, but OCaml is pretty "wordy" in notation in contrast
> to the C tradition that PHP is part of.
> 
> Reintroducing "objects that pass by value" is a hard pass from me. The
> way forward is immutability and constrained mutability (ownership,
> escape analysis, etc). Psalm also supports array shapes - maybe this
> can be investigated as an alternative? Since PHP has no tuples.
> 
> I'm not convinced the added complexity of asymmetric visibility is
> powerful enough to motivate its existence. Feel free to prove me
> wrong. :) My choice here would be namespace "internal" (also supported
> by Psalm already), but this requires implementation of namespace
> visibility, a PR that was abandoned.
> 
> And also, happy new year!

Happy New Year!

I agree that "objects, but passing by value" would not be the right solution. I 
used to think that would be a good part of the solution, but eventually 
concluded that it would introduce more complexity, not less.  Eventually, 
everything people wanted to do with objects they'd want to do with "Records" 
(for lack of a better term), and if they pass by value but are still mutable 
then you have a weird situation where sometimes changes propagate and some 
don't (depending on if you have a record or object).  Making it easier to use 
objects in a value-esque way will get us closer to the desired end state.

I think the tldr of my post is this: A single "immutable" flag (whatever it's 
called) on a class or property would require having lots of holes poked in it 
in order to make it useful in practice (mostly what "initonly" would do), but 
those holes would introduce other holes we don't want (cloning an object from 
the outside when you shouldn't).

Asymmetric visibility, however, doesn't give us true immutability but allows a 
class author to more easily emulate it "close enough", while also supporting 
various other use cases.  Its gap is the class author, not the entire rest of 
the programming industry.  That makes it much safer, and gets us to objects 
that are effectively immutable from the outside, which is what's important.  
(If they're mutable from the inside, either there are use cases for that or 
rely on the good behavior of just the class author, who is in the best position 
to know if the object should be internally immutable or not.)

Pairing that with an easy clone-with-change syntax would allow class authors to 
easily construct something that is immutable-in-practice fairly easily, even if 
it's not Twue Immutability(tm).

--Larry Garfield

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-01-01 Thread Olle Härstedt
2021-01-01 19:14 GMT, Larry Garfield :
> On Thu, Dec 31, 2020, at 8:04 AM, Olle Härstedt wrote:
>> 2020-12-31 12:37 GMT, Rowan Tommins :
>
>> > On 30/12/2020 18:42, Olle Härstedt wrote:
>> >>> To put it a different way, value types naturally form*expressions*,
>> >>> which mutable objects model clumsily. It would be very tedious if we
>> >>> had
>> >>> to avoid accidentally mutating the speed of light:
>> >>>
>> >>> $e = (clone $m) * ((clone $c) ** 2);
>> >> Using a variable on right-hand side does not automatically create an
>> >> alias, so in the above case you don't have to use clone.
>> >
>> >
>> > Whether or not the type system forced you to, you'd have to use clone
>> > if
>> > the values were implemented as mutable. Switching to methods again may
>> > make that clearer:
>> >
>> > $c = new MyNumber(299_792_458);
>> > $m = new MyNumber(10);
>> > $e = $m->multiply( $c->square() );
>> >
>> > If multiply() and square() are mutating state, rather than returning
>> > new
>> > instances, $c is now 89875517873681764, which is going to totally mess
>> > up the universe...
>> >
>> >
>> > Regards,
>> >
>> > --
>> > Rowan Tommins
>> > [IMSoP]
>>
>> Yes, of course you can find use-cases where immutability is a better
>> choice, just like I can find use-cases where (constrained) mutability
>> is better. The point is not to replace one tool with another, but
>> rather adding another tool to the toolbox. The web dev discourse is
>> one-sided with regard to immutability, I think. Wish I had time to
>> implement a PR to Psalm to show something more concrete... Again, if
>> you only have a hammer, everything looks like a nail. :)
>>
>> Olle
>
>> The web dev discourse is
>> one-sided with regard to immutability,
>
> Yes, if you've heard any of the regular whining about PSR-7 being an
> immutable object you'd think it's one-sided in favor of mutability. ;-)
>
> As you say, the point here is to add tools.  Right now, doing immutability
> in PHP in syntactically clumsy and ugly.  We want to fix that, and that has
> to include some means of "give me a new value based on this existing value
> but with some difference."  (aka, exactly what with-er methods do, although
> I agree entirely that if you have the option of less generic names, use
> them).
>
> So, can we get back to the original post, which is proposing specifics of
> the tools to make that happen? :-)  (Asymmetric visibility and clone-with,
> specifically.)
>

OK!

I like that you connect higher level design patterns with language
design. This is the way to go, IMO. Personally, I'd prefer support for
the Psalm notation `@psalm-readonly`, which is the same as your
initonly. Clone-with makes sense too, as this construct is already
supported in multiple languages. The exact notation doesn't matter
that much - my personal choice is OCaml {record with x = 10} over JS
spread operator, but OCaml is pretty "wordy" in notation in contrast
to the C tradition that PHP is part of.

Reintroducing "objects that pass by value" is a hard pass from me. The
way forward is immutability and constrained mutability (ownership,
escape analysis, etc). Psalm also supports array shapes - maybe this
can be investigated as an alternative? Since PHP has no tuples.

I'm not convinced the added complexity of asymmetric visibility is
powerful enough to motivate its existence. Feel free to prove me
wrong. :) My choice here would be namespace "internal" (also supported
by Psalm already), but this requires implementation of namespace
visibility, a PR that was abandoned.

And also, happy new year!

Olle

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-01-01 Thread Paul M. Jones



> On Jan 1, 2021, at 13:14, Larry Garfield  wrote:
> 
>> The web dev discourse is one-sided with regard to immutability, 
> 
> Yes, if you've heard any of the regular whining about PSR-7 being an 
> immutable object you'd think it's one-sided in favor of mutability.

To characterize it as "whining" is pretentious. The complaints against the 
incomplete and inconsistent immutability of PSR-7 have merit.

As one of the sponsors of PSR-7, I have come to regard its quasi-immutability 
as one of its main weaknesses, one that we of FIG should have (but failed) to 
predict would be more trouble than it was worth. The fewer people who use it, 
the better.


-- 
Paul M. Jones
pmjo...@pmjones.io
http://paul-m-jones.com

Modernizing Legacy Applications in PHP
https://leanpub.com/mlaphp

Solving the N+1 Problem in PHP
https://leanpub.com/sn1php

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2021-01-01 Thread Larry Garfield
On Thu, Dec 31, 2020, at 8:04 AM, Olle Härstedt wrote:
> 2020-12-31 12:37 GMT, Rowan Tommins :

> > On 30/12/2020 18:42, Olle Härstedt wrote:
> >>> To put it a different way, value types naturally form*expressions*,
> >>> which mutable objects model clumsily. It would be very tedious if we had
> >>> to avoid accidentally mutating the speed of light:
> >>>
> >>> $e = (clone $m) * ((clone $c) ** 2);
> >> Using a variable on right-hand side does not automatically create an
> >> alias, so in the above case you don't have to use clone.
> >
> >
> > Whether or not the type system forced you to, you'd have to use clone if
> > the values were implemented as mutable. Switching to methods again may
> > make that clearer:
> >
> > $c = new MyNumber(299_792_458);
> > $m = new MyNumber(10);
> > $e = $m->multiply( $c->square() );
> >
> > If multiply() and square() are mutating state, rather than returning new
> > instances, $c is now 89875517873681764, which is going to totally mess
> > up the universe...
> >
> >
> > Regards,
> >
> > --
> > Rowan Tommins
> > [IMSoP]
> 
> Yes, of course you can find use-cases where immutability is a better
> choice, just like I can find use-cases where (constrained) mutability
> is better. The point is not to replace one tool with another, but
> rather adding another tool to the toolbox. The web dev discourse is
> one-sided with regard to immutability, I think. Wish I had time to
> implement a PR to Psalm to show something more concrete... Again, if
> you only have a hammer, everything looks like a nail. :)
> 
> Olle

> The web dev discourse is
> one-sided with regard to immutability, 

Yes, if you've heard any of the regular whining about PSR-7 being an immutable 
object you'd think it's one-sided in favor of mutability. ;-)

As you say, the point here is to add tools.  Right now, doing immutability in 
PHP in syntactically clumsy and ugly.  We want to fix that, and that has to 
include some means of "give me a new value based on this existing value but 
with some difference."  (aka, exactly what with-er methods do, although I agree 
entirely that if you have the option of less generic names, use them).

So, can we get back to the original post, which is proposing specifics of the 
tools to make that happen? :-)  (Asymmetric visibility and clone-with, 
specifically.)

--Larry Garfield

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-31 Thread Olle Härstedt
2020-12-31 12:37 GMT, Rowan Tommins :
> Hi Mike and Olle,
>
>
> On 31/12/2020 00:24, Mike Schinkel wrote:
>> A different perspective is that "withX" methods require a mental
>> translation where "addX" methods do not, much like how a person whose
>> native language is English will find it a challenge to (or cannot) "think"
>> in French.
>
>
> I wonder if that's just about the choice of names, rather than the
> mutability/immutability itself?
>
>
>>> $start = MyDate::today();
>>> $end = $start->withAddedDays(5);
>>>
>>> vs
>>>
>>> $start = MyDate::today();
>>> $end = clone $start;
>>> $end->addDays(5);
>> Ignoring that you are comparing apples and oranges (scalars to objects,)
>> the latter is easier to reason about IMO.
>
>
> Ignoring the distinction between "scalar" and "object" was kind of the
> point: they are both "values", and are more naturally treated the same
> as differently.
>
>
> To take a different example, consider writing a new number type (for
> arbitrary precision, or complex numbers, or whatever), with an "add"
> method.
>
> The mutable version looks something like this:
>
> public function add($other) {
>  $this->value = $this->value + $other;
> }
>
> and has to be used like this:
>
> $start = new MyNumber(1);
> $end = clone $start;
> $end->add(5);
>
>
> The immutable version might look more like this:
>
> public function add($other) {
>  return clone $this with { value: $this->value + $other };
> }
>
> and is used like this:
>
> $start = new MyNumber(1);
> $end = $start->add(5);
>
> That's much closer to the "$end = $start + 5;" we're used to.
>
>
> On 30/12/2020 18:42, Olle Härstedt wrote:
>>> To put it a different way, value types naturally form*expressions*,
>>> which mutable objects model clumsily. It would be very tedious if we had
>>> to avoid accidentally mutating the speed of light:
>>>
>>> $e = (clone $m) * ((clone $c) ** 2);
>> Using a variable on right-hand side does not automatically create an
>> alias, so in the above case you don't have to use clone.
>
>
> Whether or not the type system forced you to, you'd have to use clone if
> the values were implemented as mutable. Switching to methods again may
> make that clearer:
>
> $c = new MyNumber(299_792_458);
> $m = new MyNumber(10);
> $e = $m->multiply( $c->square() );
>
> If multiply() and square() are mutating state, rather than returning new
> instances, $c is now 89875517873681764, which is going to totally mess
> up the universe...
>
>
> Regards,
>
> --
> Rowan Tommins
> [IMSoP]

Yes, of course you can find use-cases where immutability is a better
choice, just like I can find use-cases where (constrained) mutability
is better. The point is not to replace one tool with another, but
rather adding another tool to the toolbox. The web dev discourse is
one-sided with regard to immutability, I think. Wish I had time to
implement a PR to Psalm to show something more concrete... Again, if
you only have a hammer, everything looks like a nail. :)

Olle

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-31 Thread Rowan Tommins

Hi Mike and Olle,


On 31/12/2020 00:24, Mike Schinkel wrote:

A different perspective is that "withX" methods require a mental translation where "addX" 
methods do not, much like how a person whose native language is English will find it a challenge to (or 
cannot) "think" in French.



I wonder if that's just about the choice of names, rather than the 
mutability/immutability itself?




$start = MyDate::today();
$end = $start->withAddedDays(5);

vs

$start = MyDate::today();
$end = clone $start;
$end->addDays(5);

Ignoring that you are comparing apples and oranges (scalars to objects,) the 
latter is easier to reason about IMO.



Ignoring the distinction between "scalar" and "object" was kind of the 
point: they are both "values", and are more naturally treated the same 
as differently.



To take a different example, consider writing a new number type (for 
arbitrary precision, or complex numbers, or whatever), with an "add" method.


The mutable version looks something like this:

public function add($other) {
    $this->value = $this->value + $other;
}

and has to be used like this:

$start = new MyNumber(1);
$end = clone $start;
$end->add(5);


The immutable version might look more like this:

public function add($other) {
    return clone $this with { value: $this->value + $other };
}

and is used like this:

$start = new MyNumber(1);
$end = $start->add(5);

That's much closer to the "$end = $start + 5;" we're used to.


On 30/12/2020 18:42, Olle Härstedt wrote:

To put it a different way, value types naturally form*expressions*,
which mutable objects model clumsily. It would be very tedious if we had
to avoid accidentally mutating the speed of light:

$e = (clone $m) * ((clone $c) ** 2);

Using a variable on right-hand side does not automatically create an
alias, so in the above case you don't have to use clone.



Whether or not the type system forced you to, you'd have to use clone if 
the values were implemented as mutable. Switching to methods again may 
make that clearer:


$c = new MyNumber(299_792_458);
$m = new MyNumber(10);
$e = $m->multiply( $c->square() );

If multiply() and square() are mutating state, rather than returning new 
instances, $c is now 89875517873681764, which is going to totally mess 
up the universe...



Regards,

--
Rowan Tommins
[IMSoP]

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-30 Thread Mike Schinkel



> On Dec 30, 2020, at 1:15 PM, Rowan Tommins  wrote:
> 
> On 30/12/2020 13:49, Olle Härstedt wrote:
>> Uniqueness is when you only allow _one_ reference to an object (or
>> bucket of memory).
>> [...]
>> 
>> You can compare a builder pattern with immutability vs non-aliasing
>> (uniqueness):
>> 
>> ```
>> // Immutable
>> $b = new Builder();
>> $b = $b->withFoo()->withBar()->withBaz();
>> myfun($b);  // $b is immutable, so $b cannot be modified by myfun()
>> return $b;
>> ```
>> 
>> ```
>> // Uniqueness
>> $b = new Builder();  // class Builder is annotated as non-aliasing/unique
>> $b->addFoo();
>> $b->addBar();
>> $b->addBaz();
>> myfun(clone $b);  // HAVE TO CLONE TO NOT THROW EXCEPTION.
>> return $b;
>> ```
> 
> 
> Thanks, I can see how that solves a lot of the same problems, in a very 
> robustly analysable way.
> 
> However, from a high-level user-friendliness point of view, I think "withX" 
> methods are actually more natural than explicitly cloning mutable objects.


"User-friendliness" of this nature is in the eye of the beholder. 

A different perspective is that "withX" methods require a mental translation 
where "addX" methods do not, much like how a person whose native language is 
English will find it a challenge to (or cannot) "think" in French.


> Consider the case of defining a range: firstly, with plain integers and 
> familiar operators:
> 
> $start = 1;
> $end = $start + 5;
> 
> This models integers as immutable values, and + as an operator which returns 
> a new instance. If integers were mutable but not aliasable, we would instead 
> write something like this:
> 
> $start = 1;
> $end = clone $start;
> $end += 5; // where += would be an in-place modification, not a short-hand 
> for assignment
> 
> I think the first more naturally expresses the desired algorithm. It's 
> therefore natural to want the same for a range of dates:
> 
> $start = MyDate::today();
> $end = $start->withAddedDays(5);
> 
> vs
> 
> $start = MyDate::today();
> $end = clone $start;
> $end->addDays(5);


Ignoring that you are comparing apples and oranges (scalars to objects,) the 
latter is easier to reason about IMO.


> To put it a different way, value types naturally form *expressions*, which 
> mutable objects model clumsily. It would be very tedious if we had to avoid 
> accidentally mutating the speed of light:
> 
> $e = (clone $m) * ((clone $c) ** 2);
> 
> 
>> The guarantee in both above snippets is that myfun() DOES NOT modify
>> $b before returning it. BUT with immutability, you have to copy $b
>> three times, with uniqueness only one.
> 
> 
> I wonder if that difference can be optimised out by the compiler/OpCache: 
> detect clones that immediately replace their original, and optimise it to an 
> in-place modification. In other words, compile $foo = clone $foo with { x: 42 
> } to $foo->x = 42, even if the clone is actually in a "withX" method.

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-30 Thread Olle Härstedt
2020-12-30 21:27 GMT, Olle Härstedt :
> 2020-12-30 20:37 GMT, Larry Garfield :
>> On Wed, Dec 30, 2020, at 2:16 PM, Olle Härstedt wrote:
>>
>>> > Ok. You have a benchmark for this? I can make one otherwise, for the
>>> > query
>>> > example.
>>> >
>>> > It worries me a little that immutability is pushed into the ecosystem
>>> > as a
>>> > silver bullet. Main reason functional languages are using it is
>>> > because
>>> > ownership is a newer concept, so it hasn't been adapted as much.
>>>
>>> Tiny benchmark here:
>>> https://gist.github.com/olleharstedt/eaaf1dd40be541f84aa0f3954a0ea54a
>>>
>>> Running this on my ARM machine with PHP 7.2 gives ~1.2s for the
>>> immutable loop, ~0.35s for the mutable one, meaning immutability is
>>> ~3x as expensive performance wise. And this is for a SMALL object - I
>>> suspect the performance hit will grow the bigger the class gets (more
>>> properties to clone). Correct me if I'm wrong. :/
>>
>>
>> That's not a valid benchmark; it's comparing cloning and method
>> invocation
>> against just property sets.  The method calls are chewing up most of the
>> time there.
>>
>> Here's a more fair comparison on my laptop:
>> https://gist.github.com/Crell/848568124e25c8c83fc4da5455063bab
>>
>> Which is only ~20% slower.  And that's when dealing with very small
>> numbers,
>> so in most cases you're unlikely to notice a difference unless you really
>> are iterating over something a million times.
>>
>> I also tossed some big string properties into the class, and while the
>> total
>> time went up a bit the ratio between the two stayed about the same.
>>
>> --Larry Garfield
>
> Oh yeah. Huh. Didn't realize method calling was expensive. :) Another
> good reason to not use setters, lol. On my machine it's ~70% slower
> with "with" now (running multiple runs, using bash "time").
>
> The performance might matter when frameworks start to adapt patterns
> like this. It's already in PSR, with the HTTP message interface etc.
> Now I'm curious how OCaml and JS performs with a similar benchmark.
> Since they both have tracing GC, and PHP uses ref counting...

Benchmarks for JS and OCaml:
https://gist.github.com/olleharstedt/eaaf1dd40be541f84aa0f3954a0ea54a

In JS, it's 5x more expensive to use spread operator vs mutate the
object fields directly (or maybe node is just not optimized well on
the ARM CPU?). In OCaml, it's a ~10% difference between destructive
update (mutable fields) and cloning. No idea what to take from that.
:)

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-30 Thread Olle Härstedt
2020-12-30 20:37 GMT, Larry Garfield :
> On Wed, Dec 30, 2020, at 2:16 PM, Olle Härstedt wrote:
>
>> > Ok. You have a benchmark for this? I can make one otherwise, for the
>> > query
>> > example.
>> >
>> > It worries me a little that immutability is pushed into the ecosystem
>> > as a
>> > silver bullet. Main reason functional languages are using it is because
>> > ownership is a newer concept, so it hasn't been adapted as much.
>>
>> Tiny benchmark here:
>> https://gist.github.com/olleharstedt/eaaf1dd40be541f84aa0f3954a0ea54a
>>
>> Running this on my ARM machine with PHP 7.2 gives ~1.2s for the
>> immutable loop, ~0.35s for the mutable one, meaning immutability is
>> ~3x as expensive performance wise. And this is for a SMALL object - I
>> suspect the performance hit will grow the bigger the class gets (more
>> properties to clone). Correct me if I'm wrong. :/
>
>
> That's not a valid benchmark; it's comparing cloning and method invocation
> against just property sets.  The method calls are chewing up most of the
> time there.
>
> Here's a more fair comparison on my laptop:
> https://gist.github.com/Crell/848568124e25c8c83fc4da5455063bab
>
> Which is only ~20% slower.  And that's when dealing with very small numbers,
> so in most cases you're unlikely to notice a difference unless you really
> are iterating over something a million times.
>
> I also tossed some big string properties into the class, and while the total
> time went up a bit the ratio between the two stayed about the same.
>
> --Larry Garfield

Oh yeah. Huh. Didn't realize method calling was expensive. :) Another
good reason to not use setters, lol. On my machine it's ~70% slower
with "with" now (running multiple runs, using bash "time").

The performance might matter when frameworks start to adapt patterns
like this. It's already in PSR, with the HTTP message interface etc.
Now I'm curious how OCaml and JS performs with a similar benchmark.
Since they both have tracing GC, and PHP uses ref counting...

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-30 Thread Larry Garfield
On Wed, Dec 30, 2020, at 2:16 PM, Olle Härstedt wrote:

> > Ok. You have a benchmark for this? I can make one otherwise, for the query
> > example.
> >
> > It worries me a little that immutablility is pushed into the ecosystem as a
> > silver bullet. Main reason functional languages are using it is because
> > ownership is a newer concept, so it hasn't been adapted as much.
> 
> Tiny benchmark here:
> https://gist.github.com/olleharstedt/eaaf1dd40be541f84aa0f3954a0ea54a
> 
> Running this on my ARM machine with PHP 7.2 gives ~1.2s for the
> immutable loop, ~0.35s for the mutable one, meaning immutability is
> ~3x as expensive performance wise. And this is for a SMALL object - I
> suspect the performance hit will grow the bigger the class gets (more
> properties to clone). Correct me if I'm wrong. :/


That's not a valid benchmark; it's comparing cloning and method invocation 
against just property sets.  The method calls are chewing up most of the time 
there.

Here's a more fair comparison on my laptop: 
https://gist.github.com/Crell/848568124e25c8c83fc4da5455063bab

Which is only ~20% slower.  And that's when dealing with very small numbers, so 
in most cases you're unlikely to notice a difference unless you really are 
iterating over something a million times.

I also tossed some big string properties into the class, and while the total 
time went up a bit the ratio between the two stayed about the same.

--Larry Garfield

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-30 Thread Olle Härstedt
2020-12-30 19:50 GMT, Olle Härstedt :
> On Wed, 30 Dec 2020, 20:27 Larry Garfield,  wrote:
>
>>
>> > > That's a good summary of why immutability and with-er methods (or
>> > > some
>> > > equivalent) are more ergonomic.
>> > >
>> > > Another point to remember: Because of PHP's copy-on-write behavior,
>> full on
>> > > immutability doesn't actually waste that much memory.  It does use up
>> some,
>> > > but far less than you think.  (Again, based on the tests MWOP ran for
>> PSR-7
>> > > a ways back.)
>> >
>> > I thought copy-on-write was only for arrays, not objects?
>> >
>> > Olle
>>
>> Copy on write applies to all values; the caveat is that with objects, the
>> value being copied is the handle that points to an object in memory,
>> rather
>> than the object itself.  That means passing an object by reference can do
>> some seriously unexpected things, which is why you basically never do so.
>>
>> The point here is that if you have an object with 15 internal properties,
>> it's memory usage is 15 zvals plus one zval for the object, plus one zval
>> for the variable that points to it.  (I'm over-simplifying here.  A lot.)
>> If you pass it to a function, only the one zval for the handle is
>> duplicated, which is the same as for an integer.
>>
>> If you clone the object, you don't duplicate 15+1 zvals.  You duplicate
>> just the one zval for the object itself, which reuses the existing 15
>> internal property entries.  If in the new object you then update just the
>> third one, PHP then duplicates just that one internal zval and modifies
>> the
>> new one.  So you still are using only 18 zvals, not 36 zvals.  (Engine
>> people: Yes, I am *very* over-simplifying.  I know.)
>>
>> Basically, what in most languages would require manually implementing
>> "immutable data structures" we get for free in PHP, which is seriously
>> sweet.
>>
>> The net result is that a with-er chain like this:
>>
>> $foo2 = $foo->withBar('x')->withBaz('y')->withBeep('z');
>>
>> is way, way less expensive than it looks, both on memory and CPU.  It is
>> more expensive than setters, but not by much.
>>
>
> Ok. You have a benchmark for this? I can make one otherwise, for the query
> example.
>
> It worries me a little that immutablility is pushed into the ecosystem as a
> silver bullet. Main reason functional languages are using it is because
> ownership is a newer concept, so it hasn't been adapted as much.

Tiny benchmark here:
https://gist.github.com/olleharstedt/eaaf1dd40be541f84aa0f3954a0ea54a

Running this on my ARM machine with PHP 7.2 gives ~1.2s for the
immutable loop, ~0.35s for the mutable one, meaning immutability is
~3x as expensive performance wise. And this is for a SMALL object - I
suspect the performance hit will grow the bigger the class gets (more
properties to clone). Correct me if I'm wrong. :/

Olle

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-30 Thread Olle Härstedt
On Wed, 30 Dec 2020, 20:27 Larry Garfield,  wrote:

>
> > > That's a good summary of why immutability and with-er methods (or some
> > > equivalent) are more ergonomic.
> > >
> > > Another point to remember: Because of PHP's copy-on-write behavior,
> full on
> > > immutability doesn't actually waste that much memory.  It does use up
> some,
> > > but far less than you think.  (Again, based on the tests MWOP ran for
> PSR-7
> > > a ways back.)
> >
> > I thought copy-on-write was only for arrays, not objects?
> >
> > Olle
>
> Copy on write applies to all values; the caveat is that with objects, the
> value being copied is the handle that points to an object in memory, rather
> than the object itself.  That means passing an object by reference can do
> some seriously unexpected things, which is why you basically never do so.
>
> The point here is that if you have an object with 15 internal properties,
> it's memory usage is 15 zvals plus one zval for the object, plus one zval
> for the variable that points to it.  (I'm over-simplifying here.  A lot.)
> If you pass it to a function, only the one zval for the handle is
> duplicated, which is the same as for an integer.
>
> If you clone the object, you don't duplicate 15+1 zvals.  You duplicate
> just the one zval for the object itself, which reuses the existing 15
> internal property entries.  If in the new object you then update just the
> third one, PHP then duplicates just that one internal zval and modifies the
> new one.  So you still are using only 18 zvals, not 36 zvals.  (Engine
> people: Yes, I am *very* over-simplifying.  I know.)
>
> Basically, what in most languages would require manually implementing
> "immutable data structures" we get for free in PHP, which is seriously
> sweet.
>
> The net result is that a with-er chain like this:
>
> $foo2 = $foo->withBar('x')->withBaz('y')->withBeep('z');
>
> is way, way less expensive than it looks, both on memory and CPU.  It is
> more expensive than setters, but not by much.
>

Ok. You have a benchmark for this? I can make one otherwise, for the query
example.

It worries me a little that immutablility is pushed into the ecosystem as a
silver bullet. Main reason functional languages are using it is because
ownership is a newer concept, so it hasn't been adapted as much.

>


Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-30 Thread Chuck Adams
On Wed, Dec 30, 2020 at 12:27 PM Larry Garfield  wrote:
>
> If you clone the object, you don't duplicate 15+1 zvals.  You duplicate just 
> the one zval for the object itself, which reuses the existing 15 internal 
> property entries.  If in the new object you then update just the third one, 
> PHP then duplicates just that one internal zval and modifies the new one.  So 
> you still are using only 18 zvals, not 36 zvals.  (Engine people: Yes, I am 
> *very* over-simplifying.  I know.)
>

I've pondered hacking in something like perl's bless() to turn arrays
into value objects, but according to this it looks like an object with
clone-on-write behavior would be better, as I'm assuming arrays do a
full shallow copy: given an array of 15 entries, pass it to a
function, change one member, now you're using 15 more zvals, as
opposed to just one with an object.

Am I reading that right?

--c

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-30 Thread Larry Garfield
On Wed, Dec 30, 2020, at 12:42 PM, Olle Härstedt wrote:

> A more motivating example for uniqueness is perhaps a query builder.
> 
> ```
> $query = (new Query())
>   ->select(1)
>   ->from('foo')
>   ->where(...)
>   ->orderBy(..)
>   ->limit();
> doSomething($query);
> doSomethingElse($query);
> ```
> 
> In the above snippet, we don't know if doSomething() will change
> $query and cause a bug. The issue can be solved with an immutable
> builder, using withSelect(), withWhere(), etc, OR it's solved with
> uniqueness, forcing a clone to avoid creating a new alias (passing
> $query to a function creates an alias inside that function). The
> optimisation is the same as in my previous example, avoiding copying
> $query multiple times during build-up.

For a query builder, I probably wouldn't make it immutable anyway, myself.  If 
you really want to force that doSomething() cannot modify the object that is 
otherwise mutable, calling doSomething(clone $query) already works today and 
gets that net effect, provided that Query is safe to clone.  (Vis, has no 
service dependencies, and if it has any dependent value objects then it has a 
__clone() method that deep clones.)

> >> The guarantee in both above snippets is that myfun() DOES NOT modify
> >> $b before returning it. BUT with immutability, you have to copy $b
> >> three times, with uniqueness only one.

Yes, but with CoW those 3 copies are not that expensive, so we can most of the 
time ignore them except as a very micro-optimization.  (See previous email.)

--Larry Garfield

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-30 Thread Larry Garfield


> > That's a good summary of why immutability and with-er methods (or some
> > equivalent) are more ergonomic.
> >
> > Another point to remember: Because of PHP's copy-on-write behavior, full on
> > immutability doesn't actually waste that much memory.  It does use up some,
> > but far less than you think.  (Again, based on the tests MWOP ran for PSR-7
> > a ways back.)
> 
> I thought copy-on-write was only for arrays, not objects?
> 
> Olle

Copy on write applies to all values; the caveat is that with objects, the value 
being copied is the handle that points to an object in memory, rather than the 
object itself.  That means passing an object by reference can do some seriously 
unexpected things, which is why you basically never do so.

The point here is that if you have an object with 15 internal properties, it's 
memory usage is 15 zvals plus one zval for the object, plus one zval for the 
variable that points to it.  (I'm over-simplifying here.  A lot.)  If you pass 
it to a function, only the one zval for the handle is duplicated, which is the 
same as for an integer.

If you clone the object, you don't duplicate 15+1 zvals.  You duplicate just 
the one zval for the object itself, which reuses the existing 15 internal 
property entries.  If in the new object you then update just the third one, PHP 
then duplicates just that one internal zval and modifies the new one.  So you 
still are using only 18 zvals, not 36 zvals.  (Engine people: Yes, I am *very* 
over-simplifying.  I know.)

Basically, what in most languages would require manually implementing 
"immutable data structures" we get for free in PHP, which is seriously sweet.

The net result is that a with-er chain like this:

$foo2 = $foo->withBar('x')->withBaz('y')->withBeep('z');

is way, way less expensive than it looks, both on memory and CPU.  It is more 
expensive than setters, but not by much.

That's why I don't think the distinction between unique and immutable mentioned 
up-thread is that big of a deal in PHP, specifically.  Yes, they're different 
things, but the cost of them is not all that different because of CoW, so 
considering them separately is not as important as it would be in a language 
that doesn't automatically do CoW in the background for us.

(Whoever in the 90s decided to bake CoW into the engine, thank you.  It's an 
incredibly nice foundational feature.)

--Larry Garfield

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-30 Thread Olle Härstedt
2020-12-30 18:31 GMT, Larry Garfield :
> On Wed, Dec 30, 2020, at 12:15 PM, Rowan Tommins wrote:
>> On 30/12/2020 13:49, Olle Härstedt wrote:
>> > Uniqueness is when you only allow _one_ reference to an object (or
>> > bucket of memory).
>> > [...]
>> >
>> > You can compare a builder pattern with immutability vs non-aliasing
>> > (uniqueness):
>> >
>> > ```
>> > // Immutable
>> > $b = new Builder();
>> > $b = $b->withFoo()->withBar()->withBaz();
>> > myfun($b);  // $b is immutable, so $b cannot be modified by myfun()
>> > return $b;
>> > ```
>> >
>> > ```
>> > // Uniqueness
>> > $b = new Builder();  // class Builder is annotated as
>> > non-aliasing/unique
>> > $b->addFoo();
>> > $b->addBar();
>> > $b->addBaz();
>> > myfun(clone $b);  // HAVE TO CLONE TO NOT THROW EXCEPTION.
>> > return $b;
>> > ```
>>
>>
>> Thanks, I can see how that solves a lot of the same problems, in a very
>> robustly analysable way.
>>
>> However, from a high-level user-friendliness point of view, I think
>> "withX" methods are actually more natural than explicitly cloning
>> mutable objects.
>>
>> Consider the case of defining a range: firstly, with plain integers and
>> familiar operators:
>>
>> $start = 1;
>> $end = $start + 5;
>>
>> This models integers as immutable values, and + as an operator which
>> returns a new instance. If integers were mutable but not aliasable, we
>> would instead write something like this:
>>
>> $start = 1;
>> $end = clone $start;
>> $end += 5; // where += would be an in-place modification, not a
>> short-hand for assignment
>>
>> I think the first more naturally expresses the desired algorithm. It's
>> therefore natural to want the same for a range of dates:
>>
>> $start = MyDate::today();
>> $end = $start->withAddedDays(5);
>>
>> vs
>>
>> $start = MyDate::today();
>> $end = clone $start;
>> $end->addDays(5);
>>
>>
>> To put it a different way, value types naturally form *expressions*,
>> which mutable objects model clumsily. It would be very tedious if we had
>> to avoid accidentally mutating the speed of light:
>>
>> $e = (clone $m) * ((clone $c) ** 2);
>>
>>
>> > The guarantee in both above snippets is that myfun() DOES NOT modify
>> > $b before returning it. BUT with immutability, you have to copy $b
>> > three times, with uniqueness only one.
>
> That's a good summary of why immutability and with-er methods (or some
> equivalent) are more ergonomic.
>
> Another point to remember: Because of PHP's copy-on-write behavior, full on
> immutability doesn't actually waste that much memory.  It does use up some,
> but far less than you think.  (Again, based on the tests MWOP ran for PSR-7
> a ways back.)

I thought copy-on-write was only for arrays, not objects?

Olle

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-30 Thread Olle Härstedt
2020-12-30 18:15 GMT, Rowan Tommins :
> On 30/12/2020 13:49, Olle Härstedt wrote:
>> Uniqueness is when you only allow _one_ reference to an object (or
>> bucket of memory).
>> [...]
>>
>> You can compare a builder pattern with immutability vs non-aliasing
>> (uniqueness):
>>
>> ```
>> // Immutable
>> $b = new Builder();
>> $b = $b->withFoo()->withBar()->withBaz();
>> myfun($b);  // $b is immutable, so $b cannot be modified by myfun()
>> return $b;
>> ```
>>
>> ```
>> // Uniqueness
>> $b = new Builder();  // class Builder is annotated as non-aliasing/unique
>> $b->addFoo();
>> $b->addBar();
>> $b->addBaz();
>> myfun(clone $b);  // HAVE TO CLONE TO NOT THROW EXCEPTION.
>> return $b;
>> ```
>
>
> Thanks, I can see how that solves a lot of the same problems, in a very
> robustly analysable way.
>
> However, from a high-level user-friendliness point of view, I think
> "withX" methods are actually more natural than explicitly cloning
> mutable objects.
>
> Consider the case of defining a range: firstly, with plain integers and
> familiar operators:
>
> $start = 1;
> $end = $start + 5;
>
> This models integers as immutable values, and + as an operator which
> returns a new instance. If integers were mutable but not aliasable, we
> would instead write something like this:
>
> $start = 1;
> $end = clone $start;
> $end += 5; // where += would be an in-place modification, not a
> short-hand for assignment
>
> I think the first more naturally expresses the desired algorithm. It's
> therefore natural to want the same for a range of dates:
>
> $start = MyDate::today();
> $end = $start->withAddedDays(5);
>
> vs
>
> $start = MyDate::today();
> $end = clone $start;
> $end->addDays(5);

Sure, this is a good use-case for immutability. :)

>
>
> To put it a different way, value types naturally form *expressions*,
> which mutable objects model clumsily. It would be very tedious if we had
> to avoid accidentally mutating the speed of light:
>
> $e = (clone $m) * ((clone $c) ** 2);

Using a variable on right-hand side does not automatically create an
alias, so in the above case you don't have to use clone.

A more motivating example for uniqueness is perhaps a query builder.

```
$query = (new Query())
  ->select(1)
  ->from('foo')
  ->where(...)
  ->orderBy(..)
  ->limit();
doSomething($query);
doSomethingElse($query);
```

In the above snippet, we don't know if doSomething() will change
$query and cause a bug. The issue can be solved with an immutable
builder, using withSelect(), withWhere(), etc, OR it's solved with
uniqueness, forcing a clone to avoid creating a new alias (passing
$query to a function creates an alias inside that function). The
optimisation is the same as in my previous example, avoiding copying
$query multiple times during build-up.

>
>
>> The guarantee in both above snippets is that myfun() DOES NOT modify
>> $b before returning it. BUT with immutability, you have to copy $b
>> three times, with uniqueness only one.
>
>
> I wonder if that difference can be optimised out by the
> compiler/OpCache: detect clones that immediately replace their original,
> and optimise it to an in-place modification. In other words, compile
> $foo = clone $foo with { x: 42 } to $foo->x = 42, even if the clone is
> actually in a "withX" method.

I guess OCaml/Haskell does stuff like this, since everything is
immutable by default there. Let's ask them? Unless someone here
already knows? :)

Olle

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-30 Thread Larry Garfield
On Wed, Dec 30, 2020, at 12:15 PM, Rowan Tommins wrote:
> On 30/12/2020 13:49, Olle Härstedt wrote:
> > Uniqueness is when you only allow _one_ reference to an object (or
> > bucket of memory).
> > [...]
> >
> > You can compare a builder pattern with immutability vs non-aliasing
> > (uniqueness):
> >
> > ```
> > // Immutable
> > $b = new Builder();
> > $b = $b->withFoo()->withBar()->withBaz();
> > myfun($b);  // $b is immutable, so $b cannot be modified by myfun()
> > return $b;
> > ```
> >
> > ```
> > // Uniqueness
> > $b = new Builder();  // class Builder is annotated as non-aliasing/unique
> > $b->addFoo();
> > $b->addBar();
> > $b->addBaz();
> > myfun(clone $b);  // HAVE TO CLONE TO NOT THROW EXCEPTION.
> > return $b;
> > ```
> 
> 
> Thanks, I can see how that solves a lot of the same problems, in a very 
> robustly analysable way.
> 
> However, from a high-level user-friendliness point of view, I think 
> "withX" methods are actually more natural than explicitly cloning 
> mutable objects.
> 
> Consider the case of defining a range: firstly, with plain integers and 
> familiar operators:
> 
> $start = 1;
> $end = $start + 5;
> 
> This models integers as immutable values, and + as an operator which 
> returns a new instance. If integers were mutable but not aliasable, we 
> would instead write something like this:
> 
> $start = 1;
> $end = clone $start;
> $end += 5; // where += would be an in-place modification, not a 
> short-hand for assignment
> 
> I think the first more naturally expresses the desired algorithm. It's 
> therefore natural to want the same for a range of dates:
> 
> $start = MyDate::today();
> $end = $start->withAddedDays(5);
> 
> vs
> 
> $start = MyDate::today();
> $end = clone $start;
> $end->addDays(5);
> 
> 
> To put it a different way, value types naturally form *expressions*, 
> which mutable objects model clumsily. It would be very tedious if we had 
> to avoid accidentally mutating the speed of light:
> 
> $e = (clone $m) * ((clone $c) ** 2);
> 
> 
> > The guarantee in both above snippets is that myfun() DOES NOT modify
> > $b before returning it. BUT with immutability, you have to copy $b
> > three times, with uniqueness only one.

That's a good summary of why immutability and with-er methods (or some 
equivalent) are more ergonomic.

Another point to remember: Because of PHP's copy-on-write behavior, full on 
immutability doesn't actually waste that much memory.  It does use up some, but 
far less than you think.  (Again, based on the tests MWOP ran for PSR-7 a ways 
back.)

> I wonder if that difference can be optimised out by the 
> compiler/OpCache: detect clones that immediately replace their original, 
> and optimise it to an in-place modification. In other words, compile 
> $foo = clone $foo with { x: 42 } to $foo->x = 42, even if the clone is 
> actually in a "withX" method.

In concept, maybe?  That's well above my pay grade. :-)

--Larry Garfield

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-30 Thread Rowan Tommins

On 30/12/2020 13:49, Olle Härstedt wrote:

Uniqueness is when you only allow _one_ reference to an object (or
bucket of memory).
[...]

You can compare a builder pattern with immutability vs non-aliasing
(uniqueness):

```
// Immutable
$b = new Builder();
$b = $b->withFoo()->withBar()->withBaz();
myfun($b);  // $b is immutable, so $b cannot be modified by myfun()
return $b;
```

```
// Uniqueness
$b = new Builder();  // class Builder is annotated as non-aliasing/unique
$b->addFoo();
$b->addBar();
$b->addBaz();
myfun(clone $b);  // HAVE TO CLONE TO NOT THROW EXCEPTION.
return $b;
```



Thanks, I can see how that solves a lot of the same problems, in a very 
robustly analysable way.


However, from a high-level user-friendliness point of view, I think 
"withX" methods are actually more natural than explicitly cloning 
mutable objects.


Consider the case of defining a range: firstly, with plain integers and 
familiar operators:


$start = 1;
$end = $start + 5;

This models integers as immutable values, and + as an operator which 
returns a new instance. If integers were mutable but not aliasable, we 
would instead write something like this:


$start = 1;
$end = clone $start;
$end += 5; // where += would be an in-place modification, not a 
short-hand for assignment


I think the first more naturally expresses the desired algorithm. It's 
therefore natural to want the same for a range of dates:


$start = MyDate::today();
$end = $start->withAddedDays(5);

vs

$start = MyDate::today();
$end = clone $start;
$end->addDays(5);


To put it a different way, value types naturally form *expressions*, 
which mutable objects model clumsily. It would be very tedious if we had 
to avoid accidentally mutating the speed of light:


$e = (clone $m) * ((clone $c) ** 2);



The guarantee in both above snippets is that myfun() DOES NOT modify
$b before returning it. BUT with immutability, you have to copy $b
three times, with uniqueness only one.



I wonder if that difference can be optimised out by the 
compiler/OpCache: detect clones that immediately replace their original, 
and optimise it to an in-place modification. In other words, compile 
$foo = clone $foo with { x: 42 } to $foo->x = 42, even if the clone is 
actually in a "withX" method.



Regards,

--
Rowan Tommins
[IMSoP]

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-30 Thread Olle Härstedt
2020-12-29 21:36 GMT, Rowan Tommins :
> On 29/12/2020 10:28, Olle Härstedt wrote:
>> I just want to mention that immutability might be applied too
>> liberally in the current discourse, and in some cases, what you really
>> want is*non-aliasing*, that is, uniqueness, to solve problems related
>> to immutability. I think methods like `withX` is an anti-pattern, in
>> fact, and a symptom that you do not*really*  want immutability, but
>> rather uniqueness, at least in some cases.
>
>
> Hi Olle,
>
> I'm afraid I don't follow what you mean by "non-aliasing" and
> "uniqueness" here. Could you clarify, perhaps with some examples?
>
> Cheers,
>
> --
> Rowan Tommins
> [IMSoP]
>

Wikipedia has an article about aliasing:
https://en.wikipedia.org/wiki/Aliasing_(computing)
Also relevant: https://en.wikipedia.org/wiki/Uniqueness_type

Uniqueness is when you only allow _one_ reference to an object (or
bucket of memory).

$a = new A();
$b = $a;  // Both $a and $b point to the same place in memory, so you
have an alias

Uniqueness and immutability solves similar problems (at least in a GC
language like PHP): Spooky action at a distance, fragile composition,
rep exposure.

The are more advanced systems of ownership than just uniqueness, e.g.
Universe Types, but let's ignore that for now.
https://www.researchgate.net/publication/221321963_Ownership_transfer_in_Universe_Types

Uniqueness has the benefit of being more performant than immutability,
since it leads to less memory copy (but of course it's not certain
this performance gain matters in PHP programs).

You can compare a builder pattern with immutability vs non-aliasing
(uniqueness):

```
// Immutable
$b = new Builder();
$b = $b->withFoo()->withBar()->withBaz();
myfun($b);  // $b is immutable, so $b cannot be modified by myfun()
return $b;
```

```
// Uniqueness
$b = new Builder();  // class Builder is annotated as non-aliasing/unique
$b->addFoo();
$b->addBar();
$b->addBaz();
myfun(clone $b);  // HAVE TO CLONE TO NOT THROW EXCEPTION.
return $b;
```

The guarantee in both above snippets is that myfun() DOES NOT modify
$b before returning it. BUT with immutability, you have to copy $b
three times, with uniqueness only one. That's why I think ownership
system merits some attention, not ONLY immutability. :) Unfortunately,
it can take a looong time to force new concepts like these into common
discourse. Rust helps, obviously. The language Clean has opt-in
uniqueness (I need to read up more on it, tho). Linear types in e.g.
Haskell is also related (but is both more complex and more powerful).

I would like to add an annotation to Psalm, like @psalm-no-alias,
because this is also needed to make type-state sane. But, didn't do
much yet, only some brain farting. :)

Olle

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-30 Thread Olle Härstedt
2020-12-29 22:43 GMT, Rowan Tommins :
> On 29/12/2020 18:38, Olle Härstedt wrote:
>> Instead of shoe-horning everything into the PHP object system, did
>> anyone consider adding support for records instead, which would always
>> be immutable, and could support the spread operator for cloning-with
>> similar as in JavaScript or OCaml? They could be based on PHP arrays
>> and thus be passed by value.
>
>
> While we could create a brand new "record" or "struct" type, I think
> there are a few reasons to think it would end up *looking* more like
> objects than arrays:
>
> - we have an established syntax for declaring types of object (class Foo
> {...}), and none for declaring types of array
> - the 'bar' in $foo['bar'] is an expression, implying dynamic options;
> the bar in $foo->bar is a bare identifier, implying statically defined
> options
> - similarly, we have a syntax for creating object instances, with
> statically analysable members: new Foo(bar: 42)
>
>
> The spread operator could be made to work with either style, if we
> preferred it to using "clone ... with ...":
>
> - ['bar'=>69, ...$existingFoo]
> - new Foo(bar: 69, ...$existingFoo)
>
>
> However, arrays arguably already have a clone-with syntax, more normally
> thought of as "copy-on-write". Rather than "mutable with special logic
> to pass and assign by value", I think you can model their behaviour as
> "immutable with special logic to clone with modifications":
>
> $foo = ['bar'=>42, 'baz'=>101];
> $newFoo = $foo; // lazy assignment by value is indistinguishable from
> assignment by pointer
> $newFoo['bar'] = 69; // $newFoo is a modified clone of $foo
> $newFoo['bar'] = 72; // mutating $newFoo in place is indistinguishable
> from creating and assigning another modified clone
>
>
> In theory, "records" could have this ability with object-like syntax:
>
> $foo = new Foo(bar: 42, baz: 101);
> $newFoo = $foo;
> $newFoo->bar = 69; // $newFoo is a modified clone
> $newFoo->bar = 72; // can be optimised as in-place modification, but
> conceptually cloning again
>
>
> In the simple case, that's equivalent to a clone-with:
>
> $foo = new Foo(bar: 42, baz: 101);
> $newFoo = clone $foo with { bar: 69 };
> $newFoo = clone $newFoo with { bar: 72 }; // can probably be optimised
> the same way as the above examples
>
>
> It would allow more complex modifications, though, such as deep
> modification:
>
> $foo = new Foo(bar: new Bar(name: 'Bob'));
> $newFoo = $foo;
> $newFoo->bar->name = 'Robert';
>
> That last line would do the same as this:
>
> $newFoo = clone $newFoo with { bar: clone $newFoo->bar with { name:
> 'Robert' }};
>
> How desirable that is, and how it fits with the use cases in Larry's
> post, I'm not sure.
>
>
> Regards,
>
> --
> Rowan Tommins
> [IMSoP]
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>
>

Good breakdown. One benefit of records is that they can be
structurally typed (instead of nominally, as classes are), but that's
probably never going to happen in PHP. :) Perhaps a `readonly`
attribute is best for now? Compare with the annotation supported by
Psalm: 
https://psalm.dev/docs/annotating_code/supported_annotations/#psalm-readonly-and-readonly

Olle

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-29 Thread Rowan Tommins

On 29/12/2020 18:38, Olle Härstedt wrote:

Instead of shoe-horning everything into the PHP object system, did
anyone consider adding support for records instead, which would always
be immutable, and could support the spread operator for cloning-with
similar as in JavaScript or OCaml? They could be based on PHP arrays
and thus be passed by value.



While we could create a brand new "record" or "struct" type, I think 
there are a few reasons to think it would end up *looking* more like 
objects than arrays:


- we have an established syntax for declaring types of object (class Foo 
{...}), and none for declaring types of array
- the 'bar' in $foo['bar'] is an expression, implying dynamic options; 
the bar in $foo->bar is a bare identifier, implying statically defined 
options
- similarly, we have a syntax for creating object instances, with 
statically analysable members: new Foo(bar: 42)



The spread operator could be made to work with either style, if we 
preferred it to using "clone ... with ...":


- ['bar'=>69, ...$existingFoo]
- new Foo(bar: 69, ...$existingFoo)


However, arrays arguably already have a clone-with syntax, more normally 
thought of as "copy-on-write". Rather than "mutable with special logic 
to pass and assign by value", I think you can model their behaviour as 
"immutable with special logic to clone with modifications":


$foo = ['bar'=>42, 'baz'=>101];
$newFoo = $foo; // lazy assignment by value is indistinguishable from 
assignment by pointer

$newFoo['bar'] = 69; // $newFoo is a modified clone of $foo
$newFoo['bar'] = 72; // mutating $newFoo in place is indistinguishable 
from creating and assigning another modified clone



In theory, "records" could have this ability with object-like syntax:

$foo = new Foo(bar: 42, baz: 101);
$newFoo = $foo;
$newFoo->bar = 69; // $newFoo is a modified clone
$newFoo->bar = 72; // can be optimised as in-place modification, but 
conceptually cloning again



In the simple case, that's equivalent to a clone-with:

$foo = new Foo(bar: 42, baz: 101);
$newFoo = clone $foo with { bar: 69 };
$newFoo = clone $newFoo with { bar: 72 }; // can probably be optimised 
the same way as the above examples



It would allow more complex modifications, though, such as deep 
modification:


$foo = new Foo(bar: new Bar(name: 'Bob'));
$newFoo = $foo;
$newFoo->bar->name = 'Robert';

That last line would do the same as this:

$newFoo = clone $newFoo with { bar: clone $newFoo->bar with { name: 
'Robert' }};


How desirable that is, and how it fits with the use cases in Larry's 
post, I'm not sure.



Regards,

--
Rowan Tommins
[IMSoP]

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-29 Thread Rowan Tommins

On 29/12/2020 10:28, Olle Härstedt wrote:

I just want to mention that immutability might be applied too
liberally in the current discourse, and in some cases, what you really
want is*non-aliasing*, that is, uniqueness, to solve problems related
to immutability. I think methods like `withX` is an anti-pattern, in
fact, and a symptom that you do not*really*  want immutability, but
rather uniqueness, at least in some cases.



Hi Olle,

I'm afraid I don't follow what you mean by "non-aliasing" and 
"uniqueness" here. Could you clarify, perhaps with some examples?


Cheers,

--
Rowan Tommins
[IMSoP]

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-29 Thread Thomas Nunninger

Am 28.12.20 um 21:23 schrieb Larry Garfield:

There's been a number of discussions of late around property visibility and how 
to make objects more immutable.  Since it seems to have been well-received in 
the past, I decided to do a complete analysis and context of the various things 
that have been floated about recently.

The full writeup is here:

https://peakd.com/hive-168588/@crell/object-properties-and-immutability

I hope it proves stimulating, at least of discussion and not naps.


A really nice writeup and interesting to read.

But I have a question:


We then end up with the following combinations:

* public read, private write
* public read, private read, init write
* public none, private write
* public none, private read
* public none, private read, init write


What is the difference between

 (a) "public none, private read" and
 (b) "public none, private read, init"

write"? When will (a) be initialized?

And if there is really a useful case for (a) why is there no "public 
read, private read"?


Regards

Thomas

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-29 Thread Olle Härstedt
2020-12-29 15:38 GMT, Larry Garfield :
> On Tue, Dec 29, 2020, at 2:26 AM, Marc wrote:
>>
>> On 28.12.20 21:23, Larry Garfield wrote:
>> > There's been a number of discussions of late around property visibility
>> > and how to make objects more immutable.  Since it seems to have been
>> > well-received in the past, I decided to do a complete analysis and
>> > context of the various things that have been floated about recently.
>> >
>> > The full writeup is here:
>> >
>> > https://peakd.com/hive-168588/@crell/object-properties-and-immutability
>> >
>> > I hope it proves stimulating, at least of discussion and not naps.
>> >
>>
>> Thanks for the nice write up Larry!
>>
>> Is there a reason you didn't mention the proposal for immutable classes?
>> (probably because it never went into a final RFC)
>>
>> https://externals.io/message/94913#94913
>>
>> https://externals.io/message/79180#79180
>
> Two main reasons:
>
> 1) It's not been discussed recently (see how old the dates are on those
> messages), so I wasn't thinking about it.
>
> 2) An immutable class would in all practicality be the same as a class where
> all the properties are initonly (or writeonce, but that was already
> rejected).  So any arguments for/against initonly apply in aggregate to an
> immutable class.
>
> --Larry Garfield
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>
>

Instead of shoe-horning everything into the PHP object system, did
anyone consider adding support for records instead, which would always
be immutable, and could support the spread operator for cloning-with
similar as in JavaScript or OCaml? They could be based on PHP arrays
and thus be passed by value.

Olle

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-29 Thread Larry Garfield
On Tue, Dec 29, 2020, at 2:26 AM, Marc wrote:
> 
> On 28.12.20 21:23, Larry Garfield wrote:
> > There's been a number of discussions of late around property visibility and 
> > how to make objects more immutable.  Since it seems to have been 
> > well-received in the past, I decided to do a complete analysis and context 
> > of the various things that have been floated about recently.
> >
> > The full writeup is here:
> >
> > https://peakd.com/hive-168588/@crell/object-properties-and-immutability
> >
> > I hope it proves stimulating, at least of discussion and not naps.
> >
> 
> Thanks for the nice write up Larry!
> 
> Is there a reason you didn't mention the proposal for immutable classes?
> (probably because it never went into a final RFC)
> 
> https://externals.io/message/94913#94913
> 
> https://externals.io/message/79180#79180

Two main reasons:

1) It's not been discussed recently (see how old the dates are on those 
messages), so I wasn't thinking about it.

2) An immutable class would in all practicality be the same as a class where 
all the properties are initonly (or writeonce, but that was already rejected).  
So any arguments for/against initonly apply in aggregate to an immutable class.

--Larry Garfield

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-29 Thread Olle Härstedt
2020-12-29 8:26 GMT, Marc :
>
> On 28.12.20 21:23, Larry Garfield wrote:
>> There's been a number of discussions of late around property visibility
>> and how to make objects more immutable.  Since it seems to have been
>> well-received in the past, I decided to do a complete analysis and context
>> of the various things that have been floated about recently.
>>
>> The full writeup is here:
>>
>> https://peakd.com/hive-168588/@crell/object-properties-and-immutability
>>
>> I hope it proves stimulating, at least of discussion and not naps.
>>
>
> Thanks for the nice write up Larry!
>
> Is there a reason you didn't mention the proposal for immutable classes?
> (probably because it never went into a final RFC)
>
> https://externals.io/message/94913#94913
>
> https://externals.io/message/79180#79180
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>
>

I just want to mention that immutability might be applied too
liberally in the current discourse, and in some cases, what you really
want is *non-aliasing*, that is, uniqueness, to solve problems related
to immutability. I think methods like `withX` is an anti-pattern, in
fact, and a symptom that you do not *really* want immutability, but
rather uniqueness, at least in some cases.

Olle

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



Re: [PHP-DEV] Analysis of property visibility, immutability, and cloning proposals

2020-12-29 Thread Marc


On 28.12.20 21:23, Larry Garfield wrote:
> There's been a number of discussions of late around property visibility and 
> how to make objects more immutable.  Since it seems to have been 
> well-received in the past, I decided to do a complete analysis and context of 
> the various things that have been floated about recently.
>
> The full writeup is here:
>
> https://peakd.com/hive-168588/@crell/object-properties-and-immutability
>
> I hope it proves stimulating, at least of discussion and not naps.
>

Thanks for the nice write up Larry!

Is there a reason you didn't mention the proposal for immutable classes?
(probably because it never went into a final RFC)

https://externals.io/message/94913#94913

https://externals.io/message/79180#79180

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