Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:110024 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 54472 invoked from network); 5 May 2020 21:52:32 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 5 May 2020 21:52:32 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 2177A1804B4 for ; Tue, 5 May 2020 13:27:33 -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,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_PASS,SPF_NONE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS11403 66.111.4.0/24 X-Spam-Virus: No X-Envelope-From: Received: from out1-smtp.messagingengine.com (out1-smtp.messagingengine.com [66.111.4.25]) (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 ; Tue, 5 May 2020 13:27:32 -0700 (PDT) Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailout.nyi.internal (Postfix) with ESMTP id 99FF95C00E4 for ; Tue, 5 May 2020 16:27:31 -0400 (EDT) Received: from imap26 ([10.202.2.76]) by compute7.internal (MEProxy); Tue, 05 May 2020 16:27:31 -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=ytubti nduh6a69kqpT0xEfktlDbaxYLp8uokJiS3Us8=; b=qjEdzovBIM/Z5T0CQlgTqa EYLmblUaO883owzm7vWtabPRwuxc/EavfwoJAWw5l2PYq9rWFqflTiARDOucAEO4 t8l64em/jHjSNmznEeD9KkpZAXyCbdYS65+03ONa+9d+un9q/nwughgoKBYOOfVI UgVX6EsC2aaTGkJSPO6S+TVduolBtAP5qkYSVhMErgdCN7y25k48ubmCyCGLPL8I oM975nxYZhgtsaZ73k7jgzWOQLFMu4WJrxEWRIha3K/FbBw6YgO3luvzQnSEIjaW iQztfPhbFBpafU0Vlhya5e6Lf960w7fXHred8pf6rZaqHeHcL9D96zSW6ydtVX8Q == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduhedrjeejgdduvdcutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefofgggkfgjfhffhffvufgtsehttdertderredtnecuhfhrohhmpedfnfgrrhhr hicuifgrrhhfihgvlhgufdcuoehlrghrrhihsehgrghrfhhivghlughtvggthhdrtghomh eqnecuggftrfgrthhtvghrnhepveehhedvveejledvvefgleevffdtjeekledvkeegheff gfeivdejhffhledtudetnecuffhomhgrihhnpehphhhprdhnvghtnecuvehluhhsthgvrh fuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomheplhgrrhhrhiesghgrrhhfihgv lhguthgvtghhrdgtohhm X-ME-Proxy: Received: by mailuser.nyi.internal (Postfix, from userid 501) id 240DC14200A2; Tue, 5 May 2020 16:27:31 -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: <8dc53b46-8156-4b62-a521-d6d6fd379281@www.fastmail.com> In-Reply-To: References: <76b72148-4b3a-4a63-ab4c-245439a94823@www.fastmail.com> Date: Tue, 05 May 2020 15:27:09 -0500 To: "php internals" Content-Type: text/plain Subject: Re: [PHP-DEV] Re: [RFC] Constructor Property Promotion From: larry@garfieldtech.com ("Larry Garfield") 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. :-) Thoughts? --Larry Garfield