On Fri, Feb 21, 2020 at 11:20 PM Rowan Tommins <rowan.coll...@gmail.com> wrote:
> On 20 February 2020 14:13:58 GMT+00:00, Nikita Popov <nikita....@gmail.com> > wrote: > >Hi internals, > > > >I'd like to start the discussion on the "explicit call-site > >pass-by-reference" RFC again: > >https://wiki.php.net/rfc/explicit_send_by_ref > > > Hi Nikita, > > Thanks for putting the case for this so clearly. My instinctive reaction > is still one of frustration that the pain of removing call-site ampersands > was in vain, and I will now be asked to put most of them back in. It's also > relevant that users already find where & should and should not be used very > confusing. There is a potential "PR" cost of this change that should be > weighed against the advantages. > > I'm also not very keen on internal functions being able to do things that > can't be replicated on userland, and this RFC adds two: additional > behaviour for existing "prefer-ref" arguments, and new "prefer-value" > arguments. > I should say that this is a non-essential part of the RFC. I noticed that this RFC provides a way to solve this problem, but if we don't think it the problem is worth solving, then we don't have to solve it. The prefer-ref/prefer-val thing is indeed a bit peculiar. It's an artifact of the current way of implicit by-reference passing, where the decision of whether to pass by-value or by-reference has to be made based on an "educated guess" at the call-site. That leaves us with always-val, always-ref, prefer-val and prefer-ref as the possible passing modes. In the explicit by-ref passing regime, the latter two consolidate, and we have by-val, by-ref and "either" as the options, which is a lot more obvious. But again, I can't say I'm fully convinced myself that this is really a problem we need to solve. I don't really care about call_user_func() at all (it is entirely obsoleted by $fn()), and now that I think about it, __call() isn't really the right primitive to expose anyway. If you will allow me a little digression... Instead of having __call(), what we really should have is __get_method(). For a simple forwarding proxy, the implementation would look something like this: public function __get_method(string $name): Closure { if (method_exists($this->proxy, $name)) { return Closure::fromCallable([$this->proxy, $name]); } return null; } This solves multiple problems with one stone: First, it preserves the signature of the method we're proxying to: This is better than the solution in this RFC, because it preserves both by-ref argument passing and by-ref returns, and can validate that properly (i.e. passing a non-ref to by-ref will diagnose). Second, it makes is_callable() work precisely, because we no longer have to assume that with __call() any method is callable. Third, it makes Reflection work on the proxied method. It's possible to recover normal __call() semantics from this approach by writing something like this: public function __get_method(string $name): Closure { return function(...$args) use($name) { // Normal __call() implementation in here. }; } My current opinion is that I'd rather wait for the details of out and inout > parameters to be worked out, and reap higher gains for the same cost. For > instance, if preg_match could mark $matches as "out", I'd be more happy to > run in a mode where I needed to add a call-site keyword. > I believe we talked about this in some detail in the previous discussion on this topic. My basic stance on in/out is that it's *probably* not worth the complexity, unless it is part of an effort to eliminate references from PHP entirely (which would be hugely beneficial). Unfortunately I don't really see a clear pathway towards that. "out" parameters can remove one use-case of references, and I can see how that would work both in terms of semantics and implementation. The case of "inout" parameters is much more problematic. While these can nominally work without references, I don't see how they could do so efficiently (we would have to "move out" the value from the original location to avoid COW). Similarly, I don't have any answer to how &__get() and &offsetGet() would work without references. Regards, Nikita