On Fri, Mar 15, 2019, at 10:56 PM, Kenneth Ellis McCall wrote:
> Kenneth Ellis McCall wrote:
> > Hey all,
> >
> > I'm looking to get feedback on a RFC I want to propose.
> >
> > PHP RFC: Addition of the 'struct' data type.
> >
>
> Hey all,
>
> Hopefully this addresses the questions you had in someway, even if it's
> not a direct answer and might propose other things. Also sorry for the
> brevity.
>
> Immutability:
> My initial thought was to have the property list be immutable, such as
> you can't add or remove properties, but could change the value.
> Maybe it would be possible to do something like this:
>
> const Acme\MyStruct $myStruct = {
> ...
> };
>
> To make just the instance of the struct be fully immutable.
>
> Other options could be another type, say constStruct (say that ten times
> fast), or maybe add a const hint type (or readonly) to the properties, like:
>
> struct Acme\MyStruct {
> const int id;
> }
>
>
>
> Access:
> I think I'm leaning towards the arrow accessors.
>
>
> Making it more of class type:
> Initial thinking, and why I thought we would need this, is that I would
> like a way to not use class objects for data bags (like that you see
> with entities), since you can abuse classes (and arrays) like this:
>
> class xyz {
>
> };
>
> $a = new xyz();
> $a->def = 123;
>
> // Returns 123.
> echo $a->def;
>
> While people shouldn't do it, but because they can, they will.
>
> Types hints:
> I think having them on the left side would be the best, since it kind of
> matches what we already do.
> As for the loosely type properties, I'm kind of on the border on that. I
> really want to have strongly / statically typed hints, so it could
> enforce some better habits. On the other side, for historical
> purposes... Would definitely want to take a consensus on this.
>
>
> Validation:
> I have another item I want to bring up, but don't think it would go over
> well: https://github.com/ellisgl/PHP-RFC-Advanced-Type-Hint-Validors
>
>
> Array / Class features:
> When I wrote, 'resembles a mix of a class and an array' I was thinking
> loosely around the styling, accessing properties and errors.
>
>
> Copy on Write or pass by reference/value:
> I think I'm more with Levi with the "pass by-value with copy-on-write
> semantics", of course, since this is still draft mode, it could go
> another way after further investigation and testing during implementation.
Hi Kenneth.
I'm a loud proponent of more formally defined data structures in general, so
I'm very much on board in concept. However, *almost* all of what you describe
either can be done with classes today, has been proposed to add to classes
already even if it hasn't passed yet, or could be added to classes just as
easily. I've actually started using public-property classes as essentially
this sort of struct recently, and for non-API use I quite like it.
1) As of PHP 7.4, class properties can be typed.
2) Union/compound types have been discussed many times; if they ever get
adopted they would no doubt be adopted universally and not specific to just one
data structure type. (Viz, they'd work on classes, parameter types, and return
types, too.)
3) There was a proposal on list less than a week ago to add a "locked" marker
for classes to prevent the addition of properties at runtime. The reception
was positive although it's obviously not a guarantee to pass. (I'm in favor.)
4) The "set properties in place of a constructor" approach is totally
compatible with classes as well, at least in concept. It could also help with
the common "my constructor does nothing but set properties to same-named
constructor params" pattern. I'm sure someone would propose adding it to
classes as well very shortly after it was added to a new "struct" type.
5) IMO, the previously proposed (~2-3 years ago?) property accessor RFC would
be a superior way to handle property-level access control. In short, it would
allow for Javascript-esque get/set methods that behave like properties, but you
can lock down their type and their public/private/protected; thus a private
set() method would effectively render a property read-only to the outside
world. IIRC it failed mainly due to performance concerns; (I don't know the
engine well enough to suggest a way around them at this point.) But that would
effectively allow read-only properties on classes.
The one exception is the passing and modification semantics, which are two
different things.
On the one hand, there's the passing semantics. As others have noted, objects
currently pass by handle (which means they feel like they're by reference even
though they're technically not), while arrays and everything else pass by
value. A pass by value "object" has its advantages, no question, but there are
ways around that. For example, PSR-7 request/response objects kicked off the
idea of "evolvable" objects; their "mutator" method (with*()) only ever
clone-and-return-modified (similar to DateTimeImmutable), so even though they
technically pass by handle you don't have to worry about
spooky-action-at-a-distance.
However, that dovetails into the question of property mutability (modification
semantics). Assuming object-like syntax for the moment:
struct MyStruct {
string $foo;
int $count = 5;
}
$m = new MyStruct{foo: 'bar'};
$m->foo = 'baz';
Is that legal? It's definitely not "immutable" behavior by any standard
definition of that term. However, if you don't allow that then you have an
object that is truly immutable, which means of fairly little use. You'd need
to invent some new syntax for "create a new struct instance that is just like
this other one except for..." Off the top of my head I can think of two
possibilities:
$n = $m{ foo: 'baz'};
$n = $m->foo = 'baz';
In both cases, $n is now foo: 'baz', count: 5. Both feel kind of icky to me,
even if the second weren't highly confusing with object syntax. Of course, if
that were resolved nicely for structs I give it about 12 seconds after structs
are approved before someone asks for the same capabilities for classes.
Of course, there's a second problem. I give it about another 14 seconds after
structs are approved before someone asks for methods on structs, because even
with typed properties you can still very easily run into data inconsistency
problems; a string that doesn't match a required phone number format, or a
property that should update when some other property does, etc. So we'd need
to think about adding methods to structs (which is something that C++, Go,
Rust, etc. all support... because structs and objects are the same thing in
those languages, more or less). At which point... we basically just have
objects with PHP4-style passing semantics. :-)
So if the net result is that we eventually end up with "structs are objects
that pass funny", it would be far less effort and confusion, IMO, to simply
allow for "objects that pass funny" as a first class thing; everything else
described here either is already the case for objects or if added to structs
would get added to objects sooner or later.
I don't know that simply adding a byval keyword to a class definition would be
the way to go about it; maybe using the `struct` keyword in place of `class`
but otherwise being identical? As others have noted there's ample potential
for confusion there when using an object/struct that may not pass as intended.
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.
--Larry Garfield
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php