Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:109245 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 2697 invoked from network); 23 Mar 2020 20:39:53 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 23 Mar 2020 20:39:53 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 6B148180547 for ; Mon, 23 Mar 2020 12:04:07 -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 wout2-smtp.messagingengine.com (wout2-smtp.messagingengine.com [64.147.123.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 ; Mon, 23 Mar 2020 12:04:06 -0700 (PDT) Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailout.west.internal (Postfix) with ESMTP id 6C855776 for ; Mon, 23 Mar 2020 15:04:05 -0400 (EDT) Received: from imap26 ([10.202.2.76]) by compute7.internal (MEProxy); Mon, 23 Mar 2020 15:04:05 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=content-transfer-encoding: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=sfH7cEPysoX5LrbGfIdCmuHUfvSgUl04ut+A3X9FR OY=; b=xmADCh3bWZ2MkKRtFu/9gV0V7pWzj1SgId8btFD1QBsdTOc1KoZjqjOxp UXwQVtxp3LsRx7q+G/7G696zCagSO3cxWbywi3SYA5d83r36F/mfhIX53JQZX6m8 kk+hoc/Lw7Xx4fCtnJXNdvMoUbezn2lMZQi2FNtO0MQXL2wxkmwDOthqLFAcAL+a ZzGx1laryzRj447pzYkQL/L76mj6KXWXYicC31n/4c+vGmfRznmfGxZhmvoULWR+ 14mqyUJSqsR2LyMuMhQrP99Ni60X19/aB9yvsBPz7NV/G2Yntular2fL7X/v6az2 M/ttR1R9HOkcppUrR/gwqQgHQUCmg== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudegkedguddulecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefofgggkfgjfhffhffvufgtgfesthhqredtreerjeenucfhrhhomhepfdfn rghrrhihucfirghrfhhivghlugdfuceolhgrrhhrhiesghgrrhhfihgvlhguthgvtghhrd gtohhmqeenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhm pehlrghrrhihsehgrghrfhhivghlughtvggthhdrtghomh X-ME-Proxy: Received: by mailuser.nyi.internal (Postfix, from userid 501) id 6C85B14200A2; Mon, 23 Mar 2020 15:04:04 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.1.7-1021-g152deaf-fmstable-20200319v1 Mime-Version: 1.0 Message-ID: <0af67f9d-ce2a-476f-abad-385080ce14e8@www.fastmail.com> In-Reply-To: References: <1b781e1e-3f27-485b-ab47-5eeaf9496548@www.fastmail.com> Date: Mon, 23 Mar 2020 14:03:42 -0500 To: "php internals" Content-Type: text/plain;charset=utf-8 Content-Transfer-Encoding: quoted-printable Subject: Re: [PHP-DEV] Improving PHP's Object Egonomics: A broad analysis From: larry@garfieldtech.com ("Larry Garfield") Merging some replies together here... On Sun, Mar 22, 2020, at 8:36 PM, Levi Morrison via internals wrote: > > In short: I believe our biggest potential win is to focus on 3 RFCs:= > > > > * Constructor Promotion > I would vote yes on this, assuming the implementation is sane. On Mon, Mar 23, 2020, at 12:55 AM, Micha=C5=82 Brzuchalski wrote: > That still doesn't resolve issue with lot of boilerplate when you deal= with > small objects for which public readonly is enough like object-initiali= zer > could. So I'm not sure about my vote here. It does solve only one narr= ow > situation for me. The value here is combining constructor promotion with named parameters.= Constructor promotion itself is useful for the class implementer, but = doesn't help the caller. Named parameters helps the caller, but doesn't= really help the class implementer. The combination of both of them tog= ether gives us something similar to the object-initializer syntax as a n= et result, but with many other benefits because it's not a one-off synta= x. So with the two of them together, you get: class Point { public function __construct({public int $x, public int $y}); } Which then allows any of these construction mechanisms: $p1 =3D new Point(5, 7); $p2 =3D new Point({x: 5, y: 7}); $p3 =3D new Point({y: 7, x: 5}); All of which result in an object you can use the same way: print $p1->x . ', '. $p1->y; > > * Named parameters > This one is tricky -- there are tradeoffs of every approach I've seen > proposed. I have an idea for another way to address this space, but it= > too has drawbacks; there's inherently no free lunch here, I think. Please share. I make no claim of being fully versed in the implementati= on details of how these would work at the engine level, only at the synt= ax level. > > * Compound Property Visibility > What is this last one? I searched for "compound" in the article, but > did not get many hits, none of which described what it actually _is_. Mm, yeah, I sorta changed names on that part way through. That's the "d= ifferent visibility for read and for write" proposal that Nicolas mentio= ned in the readonly thread, for which I borrowed the syntax from the pro= perty accessors RFC. On Mon, Mar 23, 2020, at 1:07 AM, Mike Schinkel wrote: > 1. Your post mentions validation needed for value objects =E2=80=94 a = concern I=20 > share =E2=80=94 but AFAICT your conclusion does not address the issue.= It doesn't directly in a syntactic way. Rather, it allows the construct= or and Setter/Wither methods to still exist as now, and users can write = what they want in there. That is, it's no change from now. That was on= e of my evaluation criteria: Improve as many of these as possible withou= t making any of them worse.. This is one were "nothing is made worse". > 2. It also mentions overlapping concerns and references numerous RFCs,= =20 > but there were two other relative works not mentioned. One[1] is an RF= C=20 > and the other[2] a PR on Github. I think they both overlaps with this=20= > problem space, with the former addressing validation whereas the latte= r=20 > case potentially conflicts with constructor promotion. You are correct, I forgot about the impact of annotations (which I also = support). Off hand, I think their only issue would be in relation to th= e constructor promotion, as the resulting syntax to put a bunch of annot= ations inside the constructor definition would get... silly. That suggest we may want a different syntax for constructor promotion th= an what I proposed we borrow from Hack, but I don't think changes the ov= erall argument. > 1. You don't really address the value object vs. service object=20 > distinction, except on the periphery. Correct. This also ties into your discussion of Structs/Records as an a= lternative approach. I have considered that before, but in this writeup= ... I found nowhere that any of the possible implementations would be us= eful only for one or the other. Rather, certain features may be more us= eful to one or the other but would definitely have uses in both. At the end of the day, I think the only language-level difference betwee= n a value and service object is the passing semantics; service objects s= hould pass as they do now, while value objects would, ideally, pass in a= way more similar to arrays. However, that was off topic at this time, = and not needed. Everything else discussed would be applicable to both o= bject types, so splitting the syntax would not be helpful, just confusin= g. For instance, property accessor methods on a new Struct type would have = the exact same performance issue as they would on a Class today. The goal was to focus on the minimum amount of work we can do to get the= maximum benefit, and I don't think a new Struct type would qualify for = that. > 2. You mention the concerns about exposing parameter names as part of=20= > the API but don't address those concerns directly. I do. Specifically, making named parameters opt-in allows class/functio= n/method authors to decide if they want to make their parameter names pa= rt of the API or not. The alternative to support it on all callables pe= riod, which is also a viable option but, as noted in the writeup, techni= cally a BC change. Either approach is possible. Now that I think about it, though, named parameters and variadics may no= t play nicely at all, so we may want to force it to be opt-in only (and = incompatible with variadics). > 3. You mention get/set properties surprisingly running code but do not= =20 > address those concerns directly. That's only an issue with full property accessors, which I specifically = do not propose we implement at this time. I was trying to represent the= arguments against property accessors last time, as I remembered them; I= personally don't think it's a problem and would love to have property a= ccessors exactly as described in the RFC, if the performance issues coul= d be resolved. Since that's not what is being proposed, determining if that's even an i= ssue is not within scope. > 4. Your concept for a JSON object-like syntax for passing parameter=20= > feels incomplete to me. Unless I miss understand it is just a special=20= > syntax that only works in the context of passing arguments to a=20 > constructor, method or function, and not a first-class language=20 > element. If we were to go that route I think we would find it highly=20= > limiting. The JSON-esque syntax was one of the options previously discussed the la= st time named parameters came up. I am not wedded to it, it was just th= e most readily-available way to demonstrate named params being opt-in. = If we make them not opt-in, then there is no need for a special syntax a= t all. I was very specifically NOT trying to propose a Javascript-like Object L= iteral syntax. It's just one option among many for denoting a named par= ameters call. So, yes, it only works in the context of passing argument= s, by design, that's the point. > 5. In the section you say that "either of the following construction=20= > styles becomes possible" but you do not talk about the option of havin= g=20 > one of more of the first parameters being positional and the rest bein= g=20 > able to be passed by name, which I think would be an ideal use-case=20= > when you want to force certain parameters to always be passed but make= =20 > the rest optional. Incorrect. I specifically say in one of the notes that we could conside= r it, but it's not necessary and may be more trouble than it's worth. I= t's more in-the-weeds than I wanted to get at this stage. Specifically: "We can consider mixing positional and named parameters the way Python d= oes, but I don't think that's necessary." Regarding interaction with Delegation (a la Go, which I also agree is a= very nice feature and we wants it, precious), I'm not sure. I would ha= ve to defer to Nikita for how that would interact with constructor promo= tion. Between that and annotations we may well want to explore a differ= ent syntax than Hack, but the essential concept is the same. > 2. Going further with constructor promotion, which you join with named= =20 > parameters, how are the parameters represented inside the=20 > constructor/method/function? As different variables methods just like= =20 > current parameters? Is there no concept of automatic aggregation of=20= > those parameters into some kind of structure that could then be passed= =20 > down to other methods and functions? Yes there is; it's called $this. The whole point of constructor promoti= on is that it avoids you writing=20 $this->a =3D $a; $this->b =3D $b; $this->c =3D $c; One possible implementation in fact is to simply auto-generate those exa= ct op codes in the source as it's getting parsed. If you want to then a= dd additional logic in the constructor body that would run after those a= ssignments, cool, those still work, and the corresponding properties are= already populated for you to use if needed. --Larry Garfield