Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:125978 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by qa.php.net (Postfix) with ESMTPS id 16E5B1A00BD for ; Sun, 17 Nov 2024 21:31:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1731879232; bh=A4Ge23djbt9wC+dta9RfOO+f7mIwIfQf7Br3AtgXos0=; h=Date:From:To:In-Reply-To:References:Subject:From; b=SLx3JCo/811ZTQ/EPFNu/nlkDnTJhUST2NA+5DsmdXMw/JRc5j/uZlQT5bVszobQp BjnUqa8R8SCaHaRfZYGa5Jad/+EsKE/tGnPPuOb7OUowoM+LmwAPg05PCLLPtlRq29 whb22bfuOBNJ9erZRHRbNyUaeK8sK9CjBc1fhy5z300yegwAkWAfCJEjX6HGoUMJTk SV1aSLMSyLeldas9q2qLV0Gzdk99tNN2kHUsKjF/BUwWwdLlM0fqKMRdSbU72FjSbN VEb+qiQSq8UMvuh2mWn6qmCIuGvclJsalFDIfAlIFapIUPQl8sHaeGH+3Pc0eWLKBI IGfljK0j5rlNA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id D3E3C18003F for ; Sun, 17 Nov 2024 21:33:49 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_MISSING,HTML_MESSAGE, RCVD_IN_DNSWL_LOW,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS,SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from fhigh-a3-smtp.messagingengine.com (fhigh-a3-smtp.messagingengine.com [103.168.172.154]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Sun, 17 Nov 2024 21:33:48 +0000 (UTC) Received: from phl-compute-01.internal (phl-compute-01.phl.internal [10.202.2.41]) by mailfhigh.phl.internal (Postfix) with ESMTP id 4216B114017E for ; Sun, 17 Nov 2024 16:31:10 -0500 (EST) Received: from phl-imap-09 ([10.202.2.99]) by phl-compute-01.internal (MEProxy); Sun, 17 Nov 2024 16:31:10 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bottled.codes; h=cc:content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm1; t=1731879070; x=1731965470; bh=pp4WqX5xhb gOqp6wiYe4x+mk8kLogTYyg9FNxEEIDPk=; b=uUKwpnGv7p2bLJHI2YEx86WCIR IV8j7cFHqzxLa457purtINk3QgEiB7gCOJB2KI1up1yHrF51Rfi3ulAVPCNtBIzO mg1FM5C/DG/1eiAMnE72cPxY7qxUFyjniaBGdBGJAl6sfvomy+OTObhFUIvY/6mB 2Khd4rJ8jseuLoPpAUbXvvKmGVMzue3vTjwWwEctuQrWwGSMar6Q+JP6a9xJ6gMv lOpogIPhCnE6PxmRT9pEP9tzH2tRbZkNU1bLy36Mmy6rBcvPHRhXaoThPWC7uDID ztHyJjeR6fjPl3AY/+CjV2/ZlxvaDR3ZKMJ4IGmpC3W7MIeREHGkL5oFCqyA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t= 1731879070; x=1731965470; bh=pp4WqX5xhbgOqp6wiYe4x+mk8kLogTYyg9F NxEEIDPk=; b=TD/oMPIJcSTLGb+cMahE3DETwRyiBs6tJGlWiR/kiG7LzmKwXpq 8xfKC8wOc+hey+L4khRY9rXAxusW7eu617vK390nDORzm54ipGPzyZIyF+wOI69Q PiEt5HR1kELvoKMH+35RO9BoMTVUsQhOuqD7bSAuhb9Ed2/+U5SglZ20R9CvbmwS GlRBmLCh0+vYnRC4Lgy8yGYa8qhzufSgDlaZesmPuZYxVRXnbOEX3HC2CVof2zwU Moveo4/3ARirNIsiXqg7wxIBIoCQ5+Q17jU73LFilo1UO0pXOboBYJWP2mHFMs2m V0D13aXJYpvDvt7uQkeEHKKDvJN+Cntynrg== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefuddrvdekgddugeelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggvpdfu rfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucgoufhushhpvggtthffoh hmrghinhculdegledmnecujfgurhepofggfffhvffkjghfufgtsegrtderreertdejnecu hfhrohhmpedftfhosgcunfgrnhguvghrshdfuceorhhosgessghothhtlhgvugdrtghoug gvsheqnecuggftrfgrthhtvghrnheptdeitddvvdevhfdufffhgeelffetgeffveekheek feeluedutdeiveekvdetjedvnecuffhomhgrihhnpeefvheglhdrohhrghenucevlhhush htvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehrohgssegsohhtthhl vggurdgtohguvghspdhnsggprhgtphhtthhopedupdhmohguvgepshhmthhpohhuthdprh gtphhtthhopehinhhtvghrnhgrlhhssehlihhsthhsrdhphhhprdhnvght X-ME-Proxy: Feedback-ID: ifab94697:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id D39C9780068; Sun, 17 Nov 2024 16:31:09 -0500 (EST) X-Mailer: MessagingEngine.com Webmail Interface Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 Date: Sun, 17 Nov 2024 22:30:24 +0100 To: internals@lists.php.net Message-ID: In-Reply-To: <68eba37e-1bfe-4509-af41-112bb196415c@app.fastmail.com> References: <68eba37e-1bfe-4509-af41-112bb196415c@app.fastmail.com> Subject: Re: [PHP-DEV] RFC: Records Content-Type: multipart/alternative; boundary=293ce24b1d9c49cb9213bb55d1e13f83 From: rob@bottled.codes ("Rob Landers") --293ce24b1d9c49cb9213bb55d1e13f83 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Hello Ilija and Larry, You both touch upon some interesting and similar thoughts, and it may be= worth sharing how I arrived here; at least so we have some shared conte= xt: Personally, I feel that classes are quite bloated with features and what= feature works with what is quite confusing for new developers; I would = rather see features removed than added to them at this point. This isn't= why I chose the "record" keyword or a new syntax, to be clear. However,= it was one of many strong reasons as to why I felt it would be an ok de= viation from "tacking on more features to classes." One of the main reasons for the alternative creation syntax is because I= felt that "new" was misleading at best, and just plain wrong at worst. = It is also why I chose "&", to make it clear you are not getting "a new = one" but one that "just happens to exist with the values you asked for."= I'd be open to a different keyword or something else entirely. It's jus= t that "new" is the wrong one for records. I did explore "data classes" to a degree, and I can see why Ilija create= d the new "mutating" syntax for their RFC. It gets really weird, really = fast. Records are the other side of structs, though. They are (nearly li= terally) arrays with a class entry on them, and thus, essentially, typed= structured arrays with behavior. In fact, I was originally going to pit= ch it as such, but decided it would either stand on its own or not; but = it is what they were designed to be from the beginning; hence the short = declaration syntax. In other words, I see this being used anywhere you'd normally use a stru= ctured array but want some type safety, without all the boilerplate of c= lasses or dealing with equality. For example, DTO's, configuration, etc.= They solve a different problem than Ilija's structs, which makes more s= ense for collections, but I see records as being good candidates for val= ues in those collections. As I shopped this RFC around to coworkers, old coworkers, other maintain= ers on the projects I work on, and (nearly) random strangers on the inte= rnet, it became clear that people liked it and understood them, but want= ed more power. Things like better custom (de)serialization than what we = have with readonly classes, custom initializers for computed properties,= etc.=20 Furthermore, as I thought about these new features for records, I also t= hought about how people would use them. They would most likely start wit= h a simple record (or not), but when changing them, I also thought about= the diffs they would create in code reviews. In fact, this is a large r= eason behind the rules for traditional constructors. Adding a traditiona= l constructor to an already existing record should look exactly like tha= t in the diff, without shifting around a bunch of properties. Eventually, we ended up with the RFC you are reading today. (To be 100% transparent, some people also thought it was pointless and w= ondered what was wrong with readonly classes, but I'll come back to that= ). Now, with that context in mind... On Sun, Nov 17, 2024, at 08:21, Larry Garfield wrote: > Plus, having another fixed type creates questions any time a new featu= re is added. I think this would happen even if I scoped out some of the RFCs you hint= ed at. I don't think there is any way around this. Adding new features c= omplicates future features, and it doesn't matter where you put them. Or= rather, it matters, but not as much as you'd think. For example, my nameof RFC is basically on hiatus until we have pattern = matching. We simply lack the grammar necessary to do it correctly, and i= t doesn't seem like the place to define that grammar because then it may= pigeonhole pattern matching. I think that is fine, but these are normal= things to go through when working on an RFC, in my limited experience. My point is, we constantly have to make this decision process, and we ju= st have to 'figure it out' as we go. On Sun, Nov 17, 2024, at 01:15, Ilija Tovilo wrote: > I personally do not think immutable data structures are a good > solution to the problem, and I don't feel like we need another, > slightly shorter way to do the same thing. On Sun, Nov 17, 2024, at 08:21, Larry Garfield wrote: > As Ilija notes, immutable objects are not always the answer. I like t= hem, and use them frequently, but they're not always appropriate. And w= e already have them with either readonly classes or now private(set) (wh= ich is close enough to immutable 99.4% of the time) To be clear, this is another tool in the developer's toolbox and not mea= nt to replace classes (even readonly classes). They are strictly immutab= le value objects, which makes sense for numbers, time, custom values (se= e: the UserId example in the RFC), etc. These aren't as good for generic= collections like maps, sets, vectors, etc. or even things like services= or controllers. For these types of things, classes (or structs) make mo= re sense. Like Ilija mentioned in their email, there are significant performance o= ptimizations to be had here that are simply not possible using regular (= readonly) classes. I didn't go into detail as to how it works because it= feels like an implementation detail, but I will spend some time distill= ing this and its consequences, into the RFC, over the coming days. As a = simple illustration, there can be significant memory usage improvements: 100,000 arrays: https://3v4l.org/Z4CcV 100,000 readonly classes: https://3v4l.org/1vhNp and what we would expect from records: https://3v4l.org/4nYXG which is o= n par with the array example. Naturally, real life won't see that kind of reduction in memory consumpt= ion (nobody is creating an array of all the same items, most of the time= ), but hopefully it gives you an idea of what can be gained. On Sun, Nov 17, 2024, at 08:21, Larry Garfield wrote: > I can see the benefit of an inline constructor. Kotlin has something = similar. But I can see the benefit of it for all classes, even service = classes, not just records. (In Kotlin, it's used for service classes al= l the time.) I think this would be a good future scope. If people like it, an RFC to = extend it to regular classes makes sense. > There's already been an RFC for clone-with that works on any object; i= t just never made it to a vote. I could see an argument for an even mor= e dedicated syntax (eg, eliminate "clone" and just do "$foo with (bar: '= baz')"), but again, useful on all objects, not just records. I feel like this is similar to my nameof RFC and doomed from the start. = Classes are just too featureful to pin down what a "with" actually means= . The discussion went into depth on this, and nothing definitive came ou= t of it (IMHO). In a sense, records get a "fresh start" and can define e= xactly what it means and how it can be used. > The alternate creation syntax... OK, this one I can't really see a ben= efit to, and Ilija already noted it may cause conflicts. And from Ilija: > A small note: The $test =3D &Test(); syntax is ambiguous, as it's > already legal. https://3v4l.org/CE5rt I originally had something about this in the RFC but removed it at the l= ast minute. I'll add it back! For now, it will live in "open issues" in = case someone has a better idea. As to the reason for it, I covered it br= iefly above, but as a reminder, it boils down to my reluctance to use "n= ew" to get a record. If anyone has any better ideas, I'm open to it. And again, from Larry: > Value-based strong equality, in cases where I want that, I also want t= o be able to control it. That goes back to Jordan's operator overload R= FC, and specifying a custom =3D=3D and <=3D>. I'd rather just have that. I originally wanted to add operators. For (I hope) obvious reasons, I de= cided to just wait for them. I think something like records (with value = semantics built-in) would be much more palatable for people worried abou= t the "abuse" of operators. I'm just going to steer clear of that topic = and leave it "undefined" for now--with the expectation that someone (Jor= dan?) may come along to define operations on objects. > Value-style passing is the really interesting one, but I want to be ab= le to use it without being forced into all of the other features here. I don't think there is much way around it. You either need a special syn= tax (structs) or immutability (records). For regular classes, there is a= lways "=3D=3D" if you have control over how they are compared. Sadly, I = don't think this is possible for regular classes, but I could be wrong. And... that's a book. I'm really sorry about the length of this email, b= ut hopefully I've addressed both your questions and concerns as best I c= an. Sincerely, =E2=80=94 Rob --293ce24b1d9c49cb9213bb55d1e13f83 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable
Hello Ilija and= Larry,

You both touch upon some interesting and similar thoughts, and it may= be worth sharing how I arrived here; at least so we have some shared co= ntext:

Personally, I feel that classes are = quite bloated with features and what feature works with what is quite co= nfusing for new developers; I would rather see features removed than add= ed to them at this point. This isn't why I chose the "record" keyword or= a new syntax, to be clear. However, it was one of many strong reasons a= s to why I felt it would be an ok deviation from "tacking on more featur= es to classes."

=
One of the main reasons for the alternative creation syntax i= s because I felt that "new" was misleading at best, and just plain wrong= at worst. It is also why I chose "&", to make it clear you are not = getting "a new one" but one that "just happens to exist with the values = you asked for." I'd be open to a different keyword or something else ent= irely. It's just that "new" is the wrong one for records.

I did explore "data classes" to a degree, and I can s= ee why Ilija created the new "mutating" syntax for their RFC. It gets re= ally weird, really fast. Records are the other side of structs, though. = They are (nearly literally) arrays with a class entry on them, and thus,= essentially, typed structured arrays with behavior. In fact, I was orig= inally going to pitch it as such, but decided it would either stand on i= ts own or not; but it is what they were designed to be from the beginnin= g; hence the short declaration syntax.

= In other words, I see this being used anywhere you'd normally use a stru= ctured array but want some type safety, without all the boilerplate of c= lasses or dealing with equality. For example, DTO's, configuration, etc.= They solve a different problem than Ilija's structs, which makes more s= ense for collections, but I see records as being good candidates for val= ues in those collections.

As I shopped this= RFC around to coworkers, old coworkers, other maintainers on the projec= ts I work on, and (nearly) random strangers on the internet, it became c= lear that people liked it and understood them, but wanted more power. Th= ings like better custom (de)serialization than what we have with readonl= y classes, custom initializers for computed properties, etc.
<= div>
Furthermore, as I thought about these new features fo= r records, I also thought about how people would use them. They would mo= st likely start with a simple record (or not), but when changing them, I= also thought about the diffs they would create in code reviews. In fact= , this is a large reason behind the rules for traditional constructors. = Adding a traditional constructor to an already existing record should lo= ok exactly like that in the diff, without shifting around a bunch of pro= perties.

Eventually, we ended up with the R= FC you are reading today.

(To be 100% trans= parent, some people also thought it was pointless and wondered what was = wrong with readonly classes, but I'll come back to that).
=
Now, with that context in mind...

On Sun, Nov 17, 2024, at 08:21, Larry Garfield wrote:
Plus, having another fixed type creates ques= tions any time a new feature is added.

I think this would happen even if I scoped out some of the RFCs= you hinted at. I don't think there is any way around this. Adding new f= eatures complicates future features, and it doesn't matter where you put= them. Or rather, it matters, but not as much as you'd think.
<= div>
For example, my nameof RFC is basically on hiatus unt= il we have pattern matching. We simply lack the grammar necessary to do = it correctly, and it doesn't seem like the place to define that grammar = because then it may pigeonhole pattern matching. I think that is fine, b= ut these are normal things to go through when working on an RFC, in my l= imited experience.

My point is, we constant= ly have to make this decision process, and we just have to 'figure it ou= t' as we go.

On Sun, Nov 17, 2024, at 01:15, Il= ija Tovilo wrote:
I personally do not think immutable data structures are a good
solution to the problem, and I don't feel like we need anoth= er,
slightly shorter way to do the same thing.

On Sun, Nov 17, 2024, at 08:21, Larry Gar= field wrote:
As Ilija notes, imm= utable objects are not always the answer.  I like them, and use the= m frequently, but they're not always appropriate.  And we already h= ave them with either readonly classes or now private(set) (which is clos= e enough to immutable 99.4% of the time)

=
To be clear, this is another tool in the developer's toolbox = and not meant to replace classes (even readonly classes). They are stric= tly immutable value objects, which makes sense for numbers, time, custom= values (see: the UserId example in the RFC), etc. These aren't as good = for generic collections like maps, sets, vectors, etc. or even things li= ke services or controllers. For these types of things, classes (or struc= ts) make more sense.

Like Ilija mentio= ned in their email, there are significant performance optimizations to b= e had here that are simply not possible using regular (readonly) classes= . I didn't go into detail as to how it works because it feels like an im= plementation detail, but I will spend some time distilling this and its = consequences, into the RFC, over the coming days. As a simple illustrati= on, there can be significant memory usage improvements:
100,000 arrays: htt= ps://3v4l.org/Z4CcV
100,000 readonly classes: https://3v4l.org/1vhNp

and what we would expect from records: https://3v4l.org/4nYXG which is on par w= ith the array example.

Naturally, real life= won't see that kind of reduction in memory consumption (nobody is creat= ing an array of all the same items, most of the time), but hopefully it = gives you an idea of what can be gained.

On= Sun, Nov 17, 2024, at 08:21, Larry Garfield wrote:
I can see the benefit of an inline constructor. = ; Kotlin has something similar.  But I can see the benefit of it fo= r all classes, even service classes, not just records.  (In Kotlin,= it's used for service classes all the time.)

I think this would be a good future scope. If people lik= e it, an RFC to extend it to regular classes makes sense.
=
There's already been an RFC for= clone-with that works on any object; it just never made it to a vote.&n= bsp; I could see an argument for an even more dedicated syntax (eg, elim= inate "clone" and just do "$foo with (bar: 'baz')"), but again, useful o= n all objects, not just records.

I feel like this is similar to my nameof RFC and doomed from the star= t. Classes are just too featureful to pin down what a "with" actually me= ans. The discussion went into depth on this, and nothing definitive came= out of it (IMHO). In a sense, records get a "fresh start" and can defin= e exactly what it means and how it can be used.

=
The alternate creation syntax... OK, this= one I can't really see a benefit to, and Ilija already noted it may cau= se conflicts.

And from Il= ija:
A small note: The $test =3D= &Test(); syntax is ambiguous, as it's
already legal. = https://3v4l.org/CE5rt
<= /blockquote>

I originally had something about this in= the RFC but removed it at the last minute. I'll add it back! For now, i= t will live in "open issues" in case someone has a better idea. As to th= e reason for it, I covered it briefly above, but as a reminder, it boils= down to my reluctance to use "new" to get a record. If anyone has any b= etter ideas, I'm open to it.

And again, fro= m Larry:
Value-based strong equa= lity, in cases where I want that, I also want to be able to control it.&= nbsp; That goes back to Jordan's operator overload RFC, and specifying a= custom =3D=3D and <=3D>.  I'd rather just have that.

I originally wanted to add operators.= For (I hope) obvious reasons, I decided to just wait for them. I think = something like records (with value semantics built-in) would be much mor= e palatable for people worried about the "abuse" of operators. I'm just = going to steer clear of that topic and leave it "undefined" for now--wit= h the expectation that someone (Jordan?) may come along to define operat= ions on objects.

= Value-style passing is the really interesting one, but I want to be able= to use it without being forced into all of the other features here.
=

I don't think there is much way a= round it. You either need a special syntax (structs) or immutability (re= cords). For regular classes, there is always "=3D=3D" if you have contro= l over how they are compared. Sadly, I don't think this is possible for = regular classes, but I could be wrong.

And.= .. that's a book. I'm really sorry about the length of this email, but h= opefully I've addressed both your questions and concerns as best I can.<= br>

Sincerely,

=E2=80=94 Rob
=
--293ce24b1d9c49cb9213bb55d1e13f83--