Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:109272 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 67828 invoked from network); 24 Mar 2020 15:56:03 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 24 Mar 2020 15:56:03 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id DF6C61804C5 for ; Tue, 24 Mar 2020 07:20:28 -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 out4-smtp.messagingengine.com (out4-smtp.messagingengine.com [66.111.4.28]) (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, 24 Mar 2020 07:20:28 -0700 (PDT) Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailout.nyi.internal (Postfix) with ESMTP id 83BFA5C0210 for ; Tue, 24 Mar 2020 10:20:27 -0400 (EDT) Received: from imap26 ([10.202.2.76]) by compute7.internal (MEProxy); Tue, 24 Mar 2020 10:20:27 -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=yxdKIK hIc/MW/rdhbsUxuJ2h07SIlq3xsKulYQJZBos=; b=wfktVvhYx9ot/3CR/uYAX+ 03nA/+GuGM92g6bvnOmvDMH+vmNwGFPmVUsM4VEWvjzh5YFXXzX5F7hJEb7WXILX eAVAKyzhJtvzro55PbV7g6OS2Y0D5nKyxW4hRfEybO5ZLcnxNpIur2KxGU0SQk7V 4n/sZ8h1s7UvJpW2sVq3PzeIVGzJapct4em9KF2iLoJRft5+5qawO+eqdseD0DG+ UDfYqre60S3bAcggEzJAy6+83MyWPVLZ+VBEDgws98NxX7pgDELX3cfK0MmqQ89D h1c0Gul03NphpnS/+9QrwoQqo7li3AY5qyLdzZXh5lmomoXefoMfok1xveXNFjjw == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudehuddgfeefucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepofgfggfkjghffffhvffutgesthdtredtreertdenucfhrhhomhepfdfnrghr rhihucfirghrfhhivghlugdfuceolhgrrhhrhiesghgrrhhfihgvlhguthgvtghhrdgtoh hmqeenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehl rghrrhihsehgrghrfhhivghlughtvggthhdrtghomh X-ME-Proxy: Received: by mailuser.nyi.internal (Postfix, from userid 501) id 1928414200A2; Tue, 24 Mar 2020 10:20:27 -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: In-Reply-To: References: <1b781e1e-3f27-485b-ab47-5eeaf9496548@www.fastmail.com> Date: Tue, 24 Mar 2020 09:20:06 -0500 To: "php internals" Content-Type: text/plain Subject: Re: [PHP-DEV] Improving PHP's Object Egonomics: A broad analysis From: larry@garfieldtech.com ("Larry Garfield") On Tue, Mar 24, 2020, at 6:52 AM, Nikita Popov wrote: > On Mon, Mar 23, 2020 at 1:48 AM Larry Garfield > Thanks for the write-up Larry. I like where you're going with this. > > If we were starting from a blank slate design, I would advocate for: > > a) having an object initializer syntax > b) not having first-class constructors at all > c) using named constructors instead. > > This also happens to be exactly what Rust does, go figure... Unfortunately > this kind of approach is hard to retrofit into PHP, because we already have > constructors, almost all classes define them, and it's hard to reconcile > object initialization syntax and non-trivial constructors in a meaningful > way. Combining this with the "no public properties" cargo cult we have > inherited from Java, the paradigm shift is probably too large here. If wishes were horses, I'd agree. Though both you and Mate mentioned named constructors; I am not sure how that would play into the compacted constructor here. > If we can't have object initializers, then improving what we can do with > constructors is the next best thing :) > > I generally like the ideal of combining property declaration and > constructors. I've had this on my mind for a while already, and also > received the same suggestion from a couple of other people (I think Nicolas > was one of them?) The current amount of boilerplate that is needed is just > large enough that I will often go with a quick and simple ad-hoc array > structure rather than declaring an explicit value object type. The main > concern, as others have already mentioned, is that these inline > declarations can end up being quite verbose, especially once attributes get > involved. > > I think I will write up a quick implementation & RFC for this part, as it > seems like something we should at least consider in more detail. I look forward to it! I am quite open to alternate syntaxes that are more amenable to attributes and delegation, as long as the net result is what we're after: Less repetition so making record-like classes is easier. > Named parameters are a pretty tough topic. I think one of the main points > of contention is that they make the parameters names part of the API > contract, and as such also subject to LSP. Your proposal offers two > possible ways to side-step this: First, by making named parameters opt-in > with a special syntax {}. Second, by limiting them to constructors. The > latter variant still exposes parameter names in the API, but at least does > not require their preservation across inheritance, as constructors are > excluded from LSP. I'm somewhat torn on this, because it makes named > parameters unusable with the very large body of existing methods, and > introduces an inconsistency in which methods can use named params and which > don't. My own feeling here is that making people care about parameter names is not actually that big of a deal. You should really be caring about variable names anyway. Python seems to do fine with named parameters being part of the contract AFAIK. Especially if we could get it in for PHP 8, that's a major anyway, so I would be fine with it. The other options (opt-in or constructor only) are IMO fallbacks in case we're nervous about it, or if the parser ends up being happier with a more explicit syntax. (Gotta keep the parser happy.) > Regarding the remainder, I think that all of readonly properties, > asymmetric visibility and property accessors have their place and value, > with some overlap between them. As you already mentioned, the previous > property accessors proposal also included asymettric visibility as a > special case, and that's how I would introduce it as well. > > However, I generally think that the main value really is the readonly > properties as proposed in the recent RFC. Nowadays, a large fraction of the > classes I use are immutable value objects, for which public readonly > properties provide a much closer match to the semantics I want. > > I think that the problem with with-er methods is just that: It's a problem > with with-er methods. It's what happens when you try to shove immutability > into something that is not actually being used in an immutable manner. > Don't pretend things are immutable when they aren't... > > Regards, > Nikita I agree that Withers are solving an odd problem; however, it's the same approach that PHP itself takes already. Consider DateTimeImmutable: $d = new DateTimeImmutable(); $d2 = $d->setDate(2020, 1, 3) ->setTime(12, 45) ->setTimezone(new DateTimeZone('America/Chicago') ->modify('+1 week'); That's a Wither pattern. The names a a bit wonky for compatibility with DateTime, but that's the exact approach that Wither methods model. From a user perspective it's pretty good. If the answer to that is "well don't do that", then what's the alternative? PHP offers no other syntax for evolvable immutable objects than private properties with Wither methods. Making Wither methods harder makes evolvable immutable objects harder. Unless there's some entirely different approach I am not aware of to achieve the same goal, in which case please share. :-) Asymmetric visibility gives us the same public result as a readonly flag but doesn't break the existing Wither pattern; it means properties are still modifiable internally, but it's way easier to have self-discipline and not muck with a private property by convention than for a public property. It also flows naturally into property accessors, whereas I really don't know how a readonly flag would interact with them. --Larry Garfield