Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:104776 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 26858 invoked from network); 17 Mar 2019 20:29:00 -0000 Received: from unknown (HELO out2-smtp.messagingengine.com) (66.111.4.26) by pb1.pair.com with SMTP; 17 Mar 2019 20:29:00 -0000 Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailout.nyi.internal (Postfix) with ESMTP id 454C220F20 for ; Sun, 17 Mar 2019 13:20:11 -0400 (EDT) Received: from imap26 ([10.202.2.76]) by compute7.internal (MEProxy); Sun, 17 Mar 2019 13:20:11 -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=sASzEK 2Irioq/lpmSCbS4Wqxe2pP4PowZg7U7dYhhTM=; b=hN92kB9vuP7YHaUD+Qi+TX /AxHlfmK9DI1qN6Sh837RP1FnublvvjnK7gzJ+pq+EFezDHI3/6VhipmQzazMykL hzsPMHKmuedhBLtfAb8SSsCTFFcrtS37IUfQKztbdJ4gMosbusTiO3MQEhNBeu3L UH/z2fVFF7VAH9gSIoCkpyYQN5b7msmsBf4ShDoD5nFN6c3zr4JyebvV0GlFU4OP ANjGc2AXYnGZ4eI8NFTKj1gwvK6d/xFvd3as+wfVWsgyszK3hJt7/NP/SGXPxXsZ wnhXeJLRq6k6HJex5j/DGi21j+MzzHk/skPZRkQqKRA7zRYJuPuu5F92oNflsFpA == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedutddrheelgddutddvucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucenucfjughrpefofgggkfgjfhffhffvufgtsehttd ertderredtnecuhfhrohhmpedfnfgrrhhrhicuifgrrhhfihgvlhgufdcuoehlrghrrhih sehgrghrfhhivghlughtvggthhdrtghomheqnecurfgrrhgrmhepmhgrihhlfhhrohhmpe hlrghrrhihsehgrghrfhhivghlughtvggthhdrtghomhenucevlhhushhtvghrufhiiigv pedt X-ME-Proxy: Received: by mailuser.nyi.internal (Postfix, from userid 501) id D150CB45CC; Sun, 17 Mar 2019 13:20:10 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.1.5-976-g376b1f3-fmstable-20190314v3 Mime-Version: 1.0 X-Me-Personality: 10727885 Message-ID: <06d025ef-8174-4104-ae15-e1120b898268@www.fastmail.com> In-Reply-To: <76E04621-C003-4215-B364-DEE04A5CFFD4@gmail.com> References: <644326f6-ef68-4442-b35f-b9114cad4a5b@www.fastmail.com> <76E04621-C003-4215-B364-DEE04A5CFFD4@gmail.com> Date: Sun, 17 Mar 2019 13:20:10 -0400 To: internals@lists.php.net Content-Type: text/plain Subject: Re: [PHP-DEV] Re: [Proposal] Struct Data Types From: larry@garfieldtech.com ("Larry Garfield") On Sat, Mar 16, 2019, at 4:43 AM, Rowan Collins wrote: > On 16 March 2019 05:18:55 GMT+00:00, Larry Garfield > wrote: > >In general, though, I think beefing up objects to be "more usable as > >structs" (locked against dynamic properties, getter/setter methods, > >possibly some improved tooling for with*()-style behavior, etc.) is the > >more sustainable long-term solution than adding an entirely new > >language construct. > > > Hi Larry, > > That's a great summary, and I agree that structs make most sense viewed > as an object with special behaviours, rather than a completely separate > type. > > Native support for "evolvable" objects (withFoo methods) would be > interesting, although I'm not sure what it would look like - ideally, > it would reduce both the boilerplate of declaring them, and the > overhead of creating intermediate objects when evolving more than one > property. It's still more verbose to write than direct assignment to a > property, but no more so than calling a setter method explicitly. Ruminating on this a while, I'm not sure there's any good way to do it until/unless we have property accessor methods. With a value object, you very often do want/need to maintain some internal validity. There's ample cases where only allowing mutation/evolution (sounds like the Zerg from Starcraft) through a method is a requirement, so any approach to first class value objects will need to allow for that. Without adding special syntax, with*() methods already do that well enough that there's little need for further syntax help. At best we could automate the $that = clone($this) first line of such methods but that's not really worth the effort. The only reasonable way I see to have both with*()-style method support and value-object behavior would be something like this: $obj2 = $obj1{foo: 'bar'}; Where $obj2 is now a totally new object (give or take internal CoW behavior that is just an optimization) where the foo property is now set to 'bar'; however, if there is a setter method defined for foo then that gets called; which means the setter must be public (which raises other issues), and can do whatever additional logic or validation is needed. So the following two classes would have essentially the same semantic effect: class Stuff { protected $foo; public function withFoo($val) : Stuff { assert($val > 10); $new = clone($this); $new->foo = $val; return $new; } } $s = new Stuff(); $s2 = $s->withFoo('bar'); struct Stuff { protected $foo public set($val) { assert($val > 10); $this->foo = $val; } } $s = new Stuff{}; $s2 = $s{foo: 'bar'}; Whether that's a good approach or not I don't now, but it's the only one that I could see working. And just looking at the sample code above I see a lot of potential for very bad things. > One thing that hasn't been brought up yet is identity: if structs are > just a special kind of object, you would be able to compare them by > identity; if they are more like arrays, you would only be able to > compare them by value. I think not having identity would make sense, > both because of the expected use cases, and because it plays better > with copy-on-write optimisations: > > $x = new SomeStruct { foo=0 }; > $x = $y; // copy-by-value, but optimised internally to copy-on-write > var_dump($x === $y); // true? at this point, there is no new object > identity > $y->foo = 1; // copy-on-write triggers internally > var_dump($x === $y); // false? they are now separated > $y->foo = 0; > var_dump($x === $y); // false? structs are now identical again, but > separated in memory > > This is much more intuitive if structs have no identity, and any two > instances with the same values are considered identical. I agree you'd expect value structs/objects to equate like primitives, not like pointers. Perhaps this is an argument for an __equals() method? Or the previously-rejected comparison magic method RFC? --Larry Garfield