Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:110045 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 45138 invoked from network); 6 May 2020 16:32:58 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 6 May 2020 16:32:58 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 7D9411804F3 for ; Wed, 6 May 2020 08:08:10 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_LOW,SPF_HELO_PASS,SPF_NONE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS11403 64.147.123.0/24 X-Spam-Virus: No X-Envelope-From: Received: from wout1-smtp.messagingengine.com (wout1-smtp.messagingengine.com [64.147.123.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Wed, 6 May 2020 08:08:09 -0700 (PDT) Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailout.west.internal (Postfix) with ESMTP id 0350F77B for ; Wed, 6 May 2020 11:08:07 -0400 (EDT) Received: from imap26 ([10.202.2.76]) by compute7.internal (MEProxy); Wed, 06 May 2020 11:08:08 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; bh=Ta1yUm D3i7R1VOW8jBXKRzMlTZ5ugR3yeafRHZBjXyI=; b=FEvRxtrSYrhpmHsaizt3Um axWqNZrwV/jZ4MYKne7rDeDSr63I7bS7gHPxt0gMLf9oFHFDulcNRkJS4G7N9hUM nHD0xE84hZTpyb/jgnEkOlloTkB4WoNkDsFda6QUexugJ02ueFEq4HqoLZhXo1YD VshNTsDE1v0Umn2QekNNfVO22cMc5NDYZPP7x82uItJhAoK6cdp8VcTjoIFFA8qO xtADN5Uf4WmMz5Wtfiot3WkD9NoOVN376ZtDos5YudS35C6Uhl+R5b+s7tCoeKM1 3d5kHFR67SbXZmVa4VK/H3ZC53JK3kN6F0bhhmMQfM0svAsk0DAW6mmOg/KbmAFw == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduhedrjeekgdekvdcutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefofgggkfgjfhffhffvufgtsehttdertderredtnecuhfhrohhmpedfnfgrrhhr hicuifgrrhhfihgvlhgufdcuoehlrghrrhihsehgrghrfhhivghlughtvggthhdrtghomh eqnecuggftrfgrthhtvghrnhepveehhedvveejledvvefgleevffdtjeekledvkeegheff gfeivdejhffhledtudetnecuffhomhgrihhnpehphhhprdhnvghtnecuvehluhhsthgvrh fuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomheplhgrrhhrhiesghgrrhhfihgv lhguthgvtghhrdgtohhm X-ME-Proxy: Received: by mailuser.nyi.internal (Postfix, from userid 501) id 23E2314200A2; Wed, 6 May 2020 11:08:07 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.3.0-dev0-351-g9981f4f-fmstable-20200421v1 Mime-Version: 1.0 Message-ID: In-Reply-To: References: <76b72148-4b3a-4a63-ab4c-245439a94823@www.fastmail.com> <8dc53b46-8156-4b62-a521-d6d6fd379281@www.fastmail.com> Date: Wed, 06 May 2020 10:07:46 -0500 To: "php internals" Content-Type: text/plain Subject: Re: [PHP-DEV] Re: [RFC] Constructor Property Promotion From: larry@garfieldtech.com ("Larry Garfield") On Wed, May 6, 2020, at 3:31 AM, Nikita Popov wrote: > On Tue, May 5, 2020 at 10:27 PM Larry Garfield > wrote: > > > On Tue, May 5, 2020, at 7:35 AM, Nikita Popov wrote: > > > > > > > Performing validation when the getAttributes() call is performed does > > sound > > > reasonable to me. We can also add a class flag to perform this validation > > > only once (if it is successful), so the cost doesn't have to be paid by > > > every single getAttributes() consumer. > > > > > > For the purpose of this RFC, I've now updated it to say that attributes > > > will be applied to both properties and parameters ( > > > https://wiki.php.net/rfc/constructor_promotion#attributes), but with an > > > explicit note that we should change the behavior prior to the PHP 8 > > release > > > if it turns out to be problematic, e.g. with regards to an attribute > > > validation feature. I think this is something of a detail, and we'll be > > > mostly fine whichever way we chose, but it's hard to say right now which > > > option is best, in particular with regard to future attributes > > improvements. > > > > > > Regards, > > > Nikita > > > > Thinking on it further, there's something sitting in the back of my head > > that's bothering me. This helped me flesh it out. > > > > I like promotion, and think it will be great for simplifying code. > > However, as attributes show as we load more bells and whistles onto > > properties (even if they are desirable and useful bells and whistles) the > > level of conflict is going to get larger. > > > > Consider, today we have: > > > > class Point { > > protected int $x; > > protected int $y; > > > > public function __construct(int $x, int $y) { > > $this->x = $x; > > $this->y = $y; > > } > > } > > > > And this is needlessly verbose. With promotion, that simplifies to: > > > > class Point { > > public function __construct(protected int $x, protected int $y) {} > > } > > > > And this is good. There seems little dispute about that. > > > > But then we add attributes, and it starts to get a little odd: > > > > class Point { > > public function __construct( > > <> > > protected int $x, > > > > <> > > protected int $y, > > ) {} > > } > > > > And has the possible confusion between parameter attributes and property > > attributes. > > > > But... there's plenty of other things that may get added to properties. > > We've discussed the "readonly" property and the more robust assymetric > > visibility. What would that look like? > > > > class Point { > > public function __construct( > > <> > > int $x { > > public get, > > private set, > > }, > > > > <> > > int $y { > > public get, > > private set, > > }, > > ) {} > > } > > > > And that's now an awful lot of metadata to shove into, technically, a > > function signature. And if accessor methods ever happen: > > > > class Point { > > public function __construct( > > <> > > int $x { > > public get () { > > return $this->x; > > }, > > private set($new) { > > if ($new < 0) { > > throw new Exception(); > > } > > $this->x = $new; > > }, > > }, > > > > <> > > int $y { > > public get () { > > return $this->y; > > }, > > private set($new) { > > if ($new < 0) { > > throw new Exception(); > > } > > $this->y = $new; > > }, > > }, > > ) {} > > } > > > > And now we have methods defined inside a function signature, and that's > > just bizzarro. It also means at least 4 indent levels before you even get > > to the body of the methods. > > > > And there's probably other things that could get attached to properties at > > some point I'm not thinking of that someone will suggest. > > > > So I have to wonder, are we painting ourselves into a hole? Most of the > > uses I can think of for extra-metadata-properties are... overlapping with > > the case where you want to have constructor promotion. That means "well if > > you need to do fancy stuff just don't use promotion" becomes a > > non-sustainable answer, because the cases where you want both will increase > > rather than be an edge case. > > > > Is there a way we can build in an escape hatch for ourselves to avoid > > these issues, both attributes and for future extension? > > > > First idea off my head, which may or may not be good: > > > > Allow an alternate keyword to fill in the body of the constructor, but NOT > > fill in the property. You still define the property yourself and put all > > the extra metadata there. To wit: > > > > class Point { > > <> > > int $x { > > public get () { > > return $this->x; > > }, > > private set($new) { > > if ($new < 0) { > > throw new Exception(); > > } > > $this->x = $new; > > }, > > }, > > > > <> > > int $y { > > public get () { > > return $this->y; > > }, > > private set($new) { > > if ($new < 0) { > > throw new Exception(); > > } > > $this->y = $new; > > }, > > }, > > > > public function __construct(promote int $x, promote int $y) {} > > } > > > > That eliminates 2 of the 4 places you'd have to repeat the name instead of > > 3, but means the constructor isn't burdened with having to hold a > > potentially non-trivial amount of metadata. It also resolves the attribute > > question as splitting it up like this would let you do "one or the other" > > (property vs parameter). > > > > That may not be the best way, but I'm slightly uneasy with a path that > > could lead to 30 lines of property metadata squeezed into a constructor > > signature definition. :-) > > > > Hey Larry, > > At least for me, there's a pretty clear line on what is acceptable to use > with constructor promotion and what isn't: That line has been crossed when > your property declarations started to include their own {} blocks. > Constructor promotion is a short-hand notation for the cases where the > constructor boilerplate is much larger than the actual functionality. If > you have 100 lines of property declarations due to heavy accessor use, then > I think the value proposition of constructor promotion converges to zero, > because the constructor boilerplate is no longer a dominating factor. > > Regarding your last example, something similar to this has already been > proposed (and declined) in a slightly different form in > https://wiki.php.net/rfc/automatic_property_initialization: > > class Point { > public int $x { ... }; > public int $y { ... }; > > public function __construct(int $this->x, int $this->y) {} > } > > Regards, > Nikita I agree that "when it has its own block statements" is a reasonable heuristic. My concern is that I see those situations (where you'd have block statements and where promotion would be helpful because the constructor is otherwise useless) as having very high overlap. Even without full accessors, asymmetric visibility is a natural place for them to overlap. I don't have data on that (obviously, since properties don't have block statements now), just a gut feeling. I'm trying to figure out how we can plan ahead and avoid an "all or nothing" problem in the future. A "promote" keyword in the future might be an option; we don't have to fully solve it now, just make sure we're not painting ourselves into a corner. --Larry Garfield