Re: [PHP-DEV] [RFC] [DISCUSSION] Compact Object Property Assignment

  109199
March 22, 2020 02:47 jakob@givoni.dk (Jakob Givoni)
Hi Andrea, thanks for your feedback.
Let's talk about syntax then :-)

The currently suggested syntax is

 -> [
     = ,
    ...
]

The  can be an existing object:

$foo->[a = 1];

Or a new, yet anonymous, object:

(new Foo)->[a = 1];

1. The (normal) brackets
===================

The reason I think it's necessary to wrap the new Foo in brackets is
because it's a language construct and not an expression in itself.
Wrapping it in brackets make it an expression.

For example, these are both syntax errors (missing brackets):
new Foo->a = 1;
new Foo()->setA(1);

In this RFC I did not want to propose changing the lexer/parser to
make that possible, since my focus was to suggest a rather trivial
implementation. I'm open to change this view, but only if someone with
solid knowledge of internals come forward and promise that it's a good
idea.

2. The arrow
==========

When the arrow follows an object expression it suggest we're doing
something on that object, like accessing a property (set/get) or
calling a method.
There are exceptions though: When the object expression is followed by
curly or square brackets it means we're accessing it as if it were an
array:

$foo[1]
$foo{1} // Deprecated

And when it's followed by normal brackets, we're invoking it as a callable:

$foo()

I see a window of opportunity here though: Since the curly brackets
were deprecated in PHP 7.4 we could repurpose it for COPA:

$foo{a = 1, b = 2}

Is it too soon?

3. The square brackets
==================

The assignments need to be grouped together, somehow (at least I think
that's the sane thing to do?) - we cannot use curly brackets as, like
you say, that's reserved to create an expression that evaluates to a
property name:

$foo->{a =1, b = 2}; // syntax error, unexpected '='

That leaves us with either normal brackets or square brackets:

$foo->(a = 1, b = 2);
$foo->[a = 1, b = 2];

Which one is more natural when we're dealing with structure data?

4. The property name
================

All I can say is that I really don't want to add anything that is not
strictly necessary, like the arrow before each property, unless it's
adding something of actual value.
Familiarity you say... yes, I can see that, but it gets very verbose
with that leading arrow... In my opinion array literal syntax is
already too verbose for me.

5. The equals sign
==============

I don't really know why => was chosen for array assignment, since we
use simple = to assign values everywhere else. Since i prefer it less
verbose, and since we already
use = in $foo->a = 1 I think a single = is the best option.

COPA is NOT object initializer
=======================

COPA can follow any object expression and has nothing to do with
object construction in itself. You can use COPA as many times as you
like at any point in an object's life.
Though object initializer would also solve what COPA is solving, COPA
doesn't introduce any new concepts, just new syntax.
I don't know why object initializer and other similar proposals failed
in the past, but I wanted to try something different, less elaborate
and more pragmatic.
I don't know if COPA has any better chance than those that came before :-)

I am going to suggest a few alternative syntaxes that we can also vote
on, but only after they've been vetted by experienced internals
developers.

Syntax A - the initial one

Syntax B:
$foo{
  a = 1,
  b = 2,
};

Syntax C:
$foo->a = 1,
  b = 2;

Syntax D:
$foo->a = 1,
       ->b = 2;

Syntax E:
$foo->(
  a = 1,
  b = 2,
);

We can try to iterate over these as well, please let me know what you think!

On Sat, Mar 21, 2020 at 1:31 PM Andrea Faulds <ajf@ajf.me> wrote:
> > Hi, > > Jakob Givoni wrote: > > Hello Internals, > > > > I'm opening up my new RFC for discussion: > > > > https://wiki.php.net/rfc/compact-object-property-assignment > > - A pragmatic approach to object literals > > > > Let me know what you think! > > > > Best, > > Jakob > > > > I really don't like this `(new Foo)->[]` syntax for a few reasons: > > * It doesn't seem unreasonable to me to imagine that `->` could be > overloaded to take a value that isn't a string for the property name. > Of course, that would be `(new Foo)->{[]}` not `(new Foo)->[]`, but it > is too close for comfort for me. > * It looks like short array syntax, but it's not an array, in fact > it is an object, which is a similar but different thing. > * Brackets normally enclose an expression: if I have `new Foo`, I can > enclose that as `(new Foo)`, yet this is adding something extra to the > `new` expression while not being part of it? This is surprising to me. > If it affects the `new`, it should be inside the brackets. > * Do we need the brackets? > > I think there are some alternative syntaxes that could be used as > inspiration. > > C99 has a versatile feature called “designated initialisers”, which lets > you initialise not only structs but arrays: > > // Struct initialisation > struct some_struct foo = { > .bar = 1, > .baz = 2, > }; > > // Array initialisation > int bar[] = { > [0] = 1, > [1] = 2, > }; > > Notice how the syntax between the curly braces resemblance the normal > syntax for accessing and assigning to members of a type. A normal struct > member assignment on its own looks like `foo.bar = 1;`, so within the > curly braces you write `.bar = 1,`. Likewise a normal array member > assignment on its own looks like `bar[0] = 1;`, so within the curly > braces you write `[0] = 1,`. This resemblance provides familiarity for > someone seeing the syntax for the first time and provides a clue as to > what it does, and also retains the visual distinctiveness between array > and struct assignments. > > If we were to copy the C99 model, perhaps it would look something like: > > $foo = new Foo { > ->bar = 1, > ->baz = 2, > }; > > (I am assuming the call to the constructor has no arguments here, but > otherwise you would insert the normal argument list brackets before the > opening `{`. I have used `{` here like C, but perhaps `[` would be > better. There would also be the question of whether `=` should be `=>` > if we want to deliberately resemble arrays.) > > However, we don't have to be so imaginitive and adapt a similar feature, > because C# already has the exact feature you are proposing, and calls it > “object initialisers”: > > Foo foo = new Foo { > bar = 1, > baz = 2, > }; > > (I am again assuming the call to the constructor has no arguments. If > there are arguments, they go before the opening `{` in C#.) > > I am neutral on whether it's a better or worse syntax than using `->`. > > Side-note, C# even supports a special kind of anonymous classes with > “object initialisers”: > > var foo = new { > bar = 1, > baz = 2, > }; > > I think PHP won't need this given `new stdClass {` would work perfectly > well, although it would be nice to have a shorter and prettier > alternative to the current `(object)[`. > > Anyway, thanks for proposing something I have wanted for ages but never > gotten round to implementing. :) > Andrea > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php >
  109201
March 22, 2020 03:09 jakob@givoni.dk (Jakob Givoni)
I just realized that syntax C and D as proposed - without anything to
signify end of COPA - become really awkward when writing nested COPA:

$foo->
    a = 1,
    b = 2,
    c = (new Foo)->
        a = 3,
        b = 4,.
    ,
;

How do we indicate that the nested block ends and jump back to the outer one?

On Sat, Mar 21, 2020 at 9:47 PM Jakob Givoni <jakob@givoni.dk> wrote:
> > Hi Andrea, thanks for your feedback. > Let's talk about syntax then :-) > > The currently suggested syntax is > > -> [ > = , > ... > ] > > The can be an existing object: > > $foo->[a = 1]; > > Or a new, yet anonymous, object: > > (new Foo)->[a = 1]; > > 1. The (normal) brackets > =================== > > The reason I think it's necessary to wrap the new Foo in brackets is > because it's a language construct and not an expression in itself. > Wrapping it in brackets make it an expression. > > For example, these are both syntax errors (missing brackets): > new Foo->a = 1; > new Foo()->setA(1); > > In this RFC I did not want to propose changing the lexer/parser to > make that possible, since my focus was to suggest a rather trivial > implementation. I'm open to change this view, but only if someone with > solid knowledge of internals come forward and promise that it's a good > idea. > > 2. The arrow > ========== > > When the arrow follows an object expression it suggest we're doing > something on that object, like accessing a property (set/get) or > calling a method. > There are exceptions though: When the object expression is followed by > curly or square brackets it means we're accessing it as if it were an > array: > > $foo[1] > $foo{1} // Deprecated > > And when it's followed by normal brackets, we're invoking it as a callable: > > $foo() > > I see a window of opportunity here though: Since the curly brackets > were deprecated in PHP 7.4 we could repurpose it for COPA: > > $foo{a = 1, b = 2} > > Is it too soon? > > 3. The square brackets > ================== > > The assignments need to be grouped together, somehow (at least I think > that's the sane thing to do?) - we cannot use curly brackets as, like > you say, that's reserved to create an expression that evaluates to a > property name: > > $foo->{a =1, b = 2}; // syntax error, unexpected '=' > > That leaves us with either normal brackets or square brackets: > > $foo->(a = 1, b = 2); > $foo->[a = 1, b = 2]; > > Which one is more natural when we're dealing with structure data? > > 4. The property name > ================ > > All I can say is that I really don't want to add anything that is not > strictly necessary, like the arrow before each property, unless it's > adding something of actual value. > Familiarity you say... yes, I can see that, but it gets very verbose > with that leading arrow... In my opinion array literal syntax is > already too verbose for me. > > 5. The equals sign > ============== > > I don't really know why => was chosen for array assignment, since we > use simple = to assign values everywhere else. Since i prefer it less > verbose, and since we already > use = in $foo->a = 1 I think a single = is the best option. > > COPA is NOT object initializer > ======================= > > COPA can follow any object expression and has nothing to do with > object construction in itself. You can use COPA as many times as you > like at any point in an object's life. > Though object initializer would also solve what COPA is solving, COPA > doesn't introduce any new concepts, just new syntax. > I don't know why object initializer and other similar proposals failed > in the past, but I wanted to try something different, less elaborate > and more pragmatic. > I don't know if COPA has any better chance than those that came before :-) > > I am going to suggest a few alternative syntaxes that we can also vote > on, but only after they've been vetted by experienced internals > developers. > > Syntax A - the initial one > > Syntax B: > $foo{ > a = 1, > b = 2, > }; > > Syntax C: > $foo->a = 1, > b = 2; > > Syntax D: > $foo->a = 1, > ->b = 2; > > Syntax E: > $foo->( > a = 1, > b = 2, > ); > > We can try to iterate over these as well, please let me know what you think! > > On Sat, Mar 21, 2020 at 1:31 PM Andrea Faulds <ajf@ajf.me> wrote: > > > > Hi, > > > > Jakob Givoni wrote: > > > Hello Internals, > > > > > > I'm opening up my new RFC for discussion: > > > > > > https://wiki.php.net/rfc/compact-object-property-assignment > > > - A pragmatic approach to object literals > > > > > > Let me know what you think! > > > > > > Best, > > > Jakob > > > > > > > I really don't like this `(new Foo)->[]` syntax for a few reasons: > > > > * It doesn't seem unreasonable to me to imagine that `->` could be > > overloaded to take a value that isn't a string for the property name.. > > Of course, that would be `(new Foo)->{[]}` not `(new Foo)->[]`, but it > > is too close for comfort for me. > > * It looks like short array syntax, but it's not an array, in fact > > it is an object, which is a similar but different thing. > > * Brackets normally enclose an expression: if I have `new Foo`, I can > > enclose that as `(new Foo)`, yet this is adding something extra to the > > `new` expression while not being part of it? This is surprising to me. > > If it affects the `new`, it should be inside the brackets. > > * Do we need the brackets? > > > > I think there are some alternative syntaxes that could be used as > > inspiration. > > > > C99 has a versatile feature called “designated initialisers”, which lets > > you initialise not only structs but arrays: > > > > // Struct initialisation > > struct some_struct foo = { > > .bar = 1, > > .baz = 2, > > }; > > > > // Array initialisation > > int bar[] = { > > [0] = 1, > > [1] = 2, > > }; > > > > Notice how the syntax between the curly braces resemblance the normal > > syntax for accessing and assigning to members of a type. A normal struct > > member assignment on its own looks like `foo.bar = 1;`, so within the > > curly braces you write `.bar = 1,`. Likewise a normal array member > > assignment on its own looks like `bar[0] = 1;`, so within the curly > > braces you write `[0] = 1,`. This resemblance provides familiarity for > > someone seeing the syntax for the first time and provides a clue as to > > what it does, and also retains the visual distinctiveness between array > > and struct assignments. > > > > If we were to copy the C99 model, perhaps it would look something like: > > > > $foo = new Foo { > > ->bar = 1, > > ->baz = 2, > > }; > > > > (I am assuming the call to the constructor has no arguments here, but > > otherwise you would insert the normal argument list brackets before the > > opening `{`. I have used `{` here like C, but perhaps `[` would be > > better. There would also be the question of whether `=` should be `=>` > > if we want to deliberately resemble arrays.) > > > > However, we don't have to be so imaginitive and adapt a similar feature, > > because C# already has the exact feature you are proposing, and calls it > > “object initialisers”: > > > > Foo foo = new Foo { > > bar = 1, > > baz = 2, > > }; > > > > (I am again assuming the call to the constructor has no arguments. If > > there are arguments, they go before the opening `{` in C#.) > > > > I am neutral on whether it's a better or worse syntax than using `->`. > > > > Side-note, C# even supports a special kind of anonymous classes with > > “object initialisers”: > > > > var foo = new { > > bar = 1, > > baz = 2, > > }; > > > > I think PHP won't need this given `new stdClass {` would work perfectly > > well, although it would be nice to have a shorter and prettier > > alternative to the current `(object)[`. > > > > Anyway, thanks for proposing something I have wanted for ages but never > > gotten round to implementing. :) > > Andrea > > > > -- > > PHP Internals - PHP Runtime Development Mailing List > > To unsubscribe, visit: http://www.php.net/unsub.php > >