On Fri, Feb 21, 2020 at 12:05 AM Larry Garfield <la...@garfieldtech.com> wrote:
> On Thu, Feb 20, 2020, at 8:47 AM, Levi Morrison via internals wrote: > > Just chiming in to voice strong support for this RFC. This is a key > > piece toward making PHP code statically analyzable. If it becomes > > required at the call site, such as in an edition of the language, it > > will significantly enhance the ability to reason about code and > > probably make it more correct as well. As a small example, consider > > this method on an Optional type class: > > > > function map(callable $f): Optional { > > if ($this->enabled) { > > return new Optional($f($this->data)); > > } else { > > return $this; > > } > > } > > > > The intent is to return a new optional or an empty one, but if you > > pass a closure that accepts something by reference you can change the > > original, which is not intended at all. For people who defend against > > it, it requires saving `$this->data` to a local variable, then passing > > in the local. Then if the user does a call-by-reference it will affect > > the local, not the object's data. > > > If $this->data is itself an object, then you have a concern for data > manipulation (spooky action at a distance) even if it's passed by value. > Given how much data these days is objects, and thus the problem exists > regardless of whether it's by value or by reference passing, adding steps > to make pass-by-reference harder doesn't seem to help much. > If you will allow me some exaggeration, what you're basically saying here is that all the const / readonly / immutability features in (nearly) all programming languages are useless, because they (nearly) always allow for interior mutability in one way or another. "const" in JavaScript doesn't allow you to rebind the object, but you can still modify the object. Same with "final" in Java. Similar things hold in C/C++/Rust when it comes to const pointers/references to structs that contain non-const pointers/references. And of course, the "readonly" RFC for PHP that is currently under discussion has the same characteristics. What I'm trying to say here: All of these features do not guarantee recursive immutability, but that doesn't render them useless in the least. In fact, the outer-most layer is where immutability is the most important, because there's a lot of difference between $i = 0; var_dump($i); // int(0) foo($i); var_dump($i); // array(7) { ... } // WTF just happened??? and $o = new Foo(); var_dump($o); // object(Foo) #42 { xxx } foo($o); var_dump($o); // object(Foo) #42 { yyy } // Did something change in there? Doesn't really matter for this code! One of the big differences is that by-reference passing can change the *type* of the variable, while by-object passing cannot. It cannot even change object identity. On a closing note: I don't think this RFC makes passing by reference "harder" in any meaningful sense. Yes, you do need to write one extra character. In exchange, every time you read code you will immediately see that by-reference passing is used, here be dragons. Regards, Nikita