Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:106341 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 38575 invoked from network); 30 Jul 2019 12:26:14 -0000 Received: from unknown (HELO mail-lf1-f68.google.com) (209.85.167.68) by pb1.pair.com with SMTP; 30 Jul 2019 12:26:14 -0000 Received: by mail-lf1-f68.google.com with SMTP id v85so44217770lfa.6 for ; Tue, 30 Jul 2019 02:51:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=3NEELqkCNtYZTL9OG5iO/E9+hQSE2Jqr9Y23F/Z0BEg=; b=sL9yJJaW+8Dk0Gozvuwae1LUESRVgOoWkipBPvBl2Bf0yfT7CN6QBUBQKEuZgYTyT5 M6BWP/RjbRpK7jraAud1NeHdTFzAkMB5aj0gk8IC/AderZivpbup4Yr356Bzpwndr5IG FC2lQzu8Sh0vVWiSRCXUiwDP1SoAcKCedVDD9vwgsBTAExM/dlEIIN7CJBvSn/fD7I4Y C+DV/W+XpnvOk4vd2AuEkKWvKrYj5tKmtTUsllur4bQaCLwXUmHE9RTG2HQWkyyFlQQS 6EOYG3EFGSuCaXsvYhsZOQQfXHq69yUleNkWfSW5yN3N7PZGqcCp2/en8n5q4uadMSZZ TGdQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=3NEELqkCNtYZTL9OG5iO/E9+hQSE2Jqr9Y23F/Z0BEg=; b=NgRJ/vHl+l2TQY9O3KSgKzD6j5p3+hv7L8IFdGnoilxc5sgsG3tQHTETb2XPKAwxfA X3nAOQ4ew+NwCQ6TeJzRz8s/eqFzQgQCJjs4kcuUR8fFbfMGSB3/fsSpafWVElWuOYdj t3KMlGaIphPi+xhSydxEcSiFux8wno7AIA9oC2AYFVSudeoWzLS8leg12q64S9PLPtNN 9FmNGfAV2mXBHyffwpvAXQh/qAINOBa6cMk1DAaYRvfJjYbOv71xZ/iZ8ET0dd4UUsOT cdaeMhipgZIxQjRT6EA+WU4+1iwn+qHtpH4Rv6bjyvj4fMKJdtdeA673s5mi0DY//JpE do0A== X-Gm-Message-State: APjAAAV+jCXqP/gsehkagR8YJf/cFZiqYhULegFZV6AQ8jYjb5N2qsJV g1mf3fB0vndYMyFgklZDcpynz+xzk3BMNL6FCac= X-Google-Smtp-Source: APXvYqx5howl4y2ysviIMLsVKr/1+4SmKbbHRHwnkn+xF1ButlRa7qtJnagGTrBevPWTs1mFwYC4KCs2mRUUk5N0Cj4= X-Received: by 2002:ac2:4a78:: with SMTP id q24mr11391829lfp.59.1564480265208; Tue, 30 Jul 2019 02:51:05 -0700 (PDT) MIME-Version: 1.0 References: <9aba78c9-f04d-45b8-6c34-ad1c2472ef76@gmail.com> <75d04139-b944-f204-f988-959fa6f3e305@gmail.com> <8CD3B476-ABF9-4DB7-96D3-217064023854@gmail.com> In-Reply-To: Date: Tue, 30 Jul 2019 11:50:48 +0200 Message-ID: To: Rowan Collins Cc: PHP Internals List Content-Type: multipart/alternative; boundary="0000000000007747e8058ee2f2d5" Subject: Re: [PHP-DEV] [RFC] Explicit call-site send-by-ref syntax From: nikita.ppv@gmail.com (Nikita Popov) --0000000000007747e8058ee2f2d5 Content-Type: text/plain; charset="UTF-8" On Mon, Jul 29, 2019 at 5:35 PM Rowan Collins wrote: > On Mon, 29 Jul 2019 at 15:41, Nikita Popov wrote: > > > This proposal (at least combined with a declare that enforces use of > > call-site annotations) addresses that concern. out/inout parameters do > not > > address this concern, because they are an mechanism that would be used > *in > > addition* to normal by-ref passing, and as such not address any problems > it > > has. > > > > The only way I see in which out/inout would actually address the concern > > of this proposal is if out/inout were used instead of & at the call-site, > > but the parameter were still a normal reference. I don't think that's a > > good idea because it breaks symmetry between arguments and parameters, > and > > also squanders any future potential to use out/inout as a way to reduce > > reference-use in this context. > > > > Does that make sense, Rowan? To put is more compactly, what I want is an > > eventual state where given $fn($a) I have a guarantee that $a is not > going > > to be magically modified, without having to perform any global reasoning > > about what $fn may refer to. If an alternative proposal does not result > in > > this eventual state, then it is not an alternative to this proposal (but > > possibly still a valuable addition in itself). > > > > > It does, yes. I guess what I had in mind was that *in the long-term*, > out/inout parameters would replace & parameters, so rather than > declare(require_reference_at_call_site=1) you would have > declare(disable_reference_parameters=1). > Something like that could in principle address the problem, though it would enforce certain design decisions to allow reaching that eventual state. I think this is how out/inout would have to work in order to satisfy BC concerns while still allowing a declare-based mode that eliminates plain by-ref passing entirely: * All current by-ref parameters in extensions must be changed to out/inout parameters. * By default, an out/inout parameter will behave exactly like a reference parameter and there is no behavioral difference between out/inout. * Additionally, the call-site is allowed to specify out/inout. If it is specified, it must match the parameter. If it is specified, inout will generate a notice if the passed value doesn't exist (while out behaves as usual reference pass). * A declare() exists that would require require call-site out/inout annotations and prohibit calls with reference parameters (that have not been converted to out/inout). * Additional changes to type-checking for out/inout parameters in userland functions. One migration problem that would still exist is that 3rd-party libraries would also have to migrate to out/inout parameters first, before users could enable the declare() mode that disables reference-passing -- otherwise they would not be able to make use of some of the library functionality, or would have to opt-out in parts of the code. Alternatively one could allow the use of out/inout with normal reference parameters as well, in which case both out/inout would be allowed at the call-site. Whether or not it's a direct alternative to this proposal, I also worry > that out/inout parameters are somewhat mutually exclusive with it: the more > effort is spent on making reference parameters "better", the less appetite > there will be for replacing them altogether. This kind of goes both ways: There is such a thing as "good enough" and there's also the typical effect that going from a 95% solution to a 99% solution will often take many times more effort (what's the technical term for this?) In this context, "effort" isn't even the right word, it's a combination of initial implementation effort, long-term maintenance cost and possibly most importantly, language semantic complexity. Above, I have outlined a way in which out/inout could work while mostly addressing my original motivation. But is this approach really better than a simple call-site "&" annotation that flawlessly integrates into the existing reference passing system? I'm not convinced that it is. Especially if we need to introduce out/inout in a way that interoperates well with references for BC/migration purposes, the semantics become fairly complex, while (imho) not offering a lot of benefit over a simple by-reference pass. The main benefit I see would be an opportunity to fix the current interaction of references and type annotations. Every time I have discussed out/inout with people before, it has been in the context of "What would we have to do to completely remove references?" A large part of that is finding an alternative to by-reference passing that does not use references. Hack introduced inout parameters (see https://hhvm.com/blog/2018/03/15/hhvm-3.25.html) specifically to avoid the issues of reference-passing (and they behave essentially like the desugaring I mentioned in some earlier mail). But we would not get these benefits using the approach outlined above, and I don't believe we could use something significantly different while still supporting existing by-ref internal functions. This is why I don't think these two things should be mixed. Proper out/inout parameters should not have anything to do with references. I agree the behaviour of type > annotations would need deciding, but arguably that should have been true > for by-reference parameters; it's somewhat bizarre that you can write > "function foo(SomeClass &$x) { $x=42; }" The solution would probably be to > reuse the "typed references" from the typed property implementation. > > > > > > Bob has brought up another interesting issue: This proposal currently > does > > not address the case of foo(...$a), where references into $a may be added > > if foo() has by-reference parameters. The suggestion was to use > foo(&...$a) > > -- however in this case only to *allow* the use of references, not > require > > it (some args may be by-val while others may be by-ref). > > > > > There's probably a bit of a rabbit-hole if the mission is "make references > explicit". An array containing a reference can be passed by value, for > instance, so $fn($a) might not technically modify $a, but still modify > elements inside it. So it seems like we come back to "this is kind of > useful information but may not actually offer a hard guarantee". > Right, references in arrays and objects are a pretty big WTF factor (especially in how they behave with copying an cloning), but I don't really have a good answer to those. Regards, Nikita --0000000000007747e8058ee2f2d5--