[RFC]Discuss] Syntax for Arrow Functions

php.internals

Levi Morrison

9 years ago
Internals, The previous discussion thread has died down significantly and so I'd like to start a new one to refocus. This message has some redundant information by design so people don't have to reference the other thread so much. Based on the discussion there are a few different syntax choices people liked. Overall it's a feature that people seem to want but everyone seems to prefer a different syntax choice. 1. fn(params) => expr 2. function(params) => expr 3. (params) ==> expr 4. (params) => expr Note that 3 and 4 require a more powerful grammar and parser and that 4 has ambiguities. I think we can work around them by rules -- only mentioning it because its popular because of JavaScript and do not prefer this at all. Note that 1 requires a new keyword. Option 2 looks the best from that perspective but is by far the longest; remember people are partially interested in this feature because they want shorter closures which this doesn't really help. This is why everyone is so divisive. All options have drawbacks. Additionally some people don't like binding by value and would prefer ref, and others really would be against by-ref. Which brings me to an option I don't think was ever discussed on list: 5. [](params) => expr // binds no values [=](params) => expr // binds by value [&](params) => expr // binds by reference It has quite a few good qualities: - No new keywords - Can choose between reference and value - Concise - Has precedence in C++, a major language - Can be done in our existing grammar and parser[1] - Can be extended to allow explicit binding of variables: // all equivalent // y is bound by value, array by reference [&, $y]($x) => $array[] = $x + $y [=, &$array]($x) => $array[] = $x + $y And of course it does have downsides: - Symbol soup (it uses a lot of symbols) - A minor BC break. Empty arrays which are invoked as functions are currently guaranteed to be errors at runtime and would have a new valid meaning. Here's an example from inside an array literal: // error at runtime previously [ []($x) => $x ] // now an array with one item which is a closure that returns its parameter Sara pointed out that we'd need to keep a leading `=` or `&` in the array to disambiguate from our array closure form. Overall I'd prefer 1 or 5. What do you guys think? [1]: I'm pretty sure it can be done but until it's done I can't say so confidently because sometimes there are things lurking in our grammar I forget about.

Björn Larsson

9 years ago
Den 2017-05-30 kl. 19:58, skrev Levi Morrison:
> Internals, > > The previous discussion thread has died down significantly and so I'd > like to start a new one to refocus. This message has some redundant > information by design so people don't have to reference the other > thread so much. > > Based on the discussion there are a few different syntax choices > people liked. Overall it's a feature that people seem to want but > everyone seems to prefer a different syntax choice. > > 1. fn(params) => expr > 2. function(params) => expr > > 3. (params) ==> expr > 4. (params) => expr > > Note that 3 and 4 require a more powerful grammar and parser and that > 4 has ambiguities. I think we can work around them by rules -- only > mentioning it because its popular because of JavaScript and do not > prefer this at all. > > Note that 1 requires a new keyword. > > Option 2 looks the best from that perspective but is by far the > longest; remember people are partially interested in this feature > because they want shorter closures which this doesn't really help. > > This is why everyone is so divisive. All options have drawbacks. > Additionally some people don't like binding by value and would prefer > ref, and others really would be against by-ref. > > Which brings me to an option I don't think was ever discussed on list: > > 5. > [](params) => expr // binds no values > [=](params) => expr // binds by value > [&](params) => expr // binds by reference > > It has quite a few good qualities: > > - No new keywords > - Can choose between reference and value > - Concise > - Has precedence in C++, a major language > - Can be done in our existing grammar and parser[1] > - Can be extended to allow explicit binding of variables: > // all equivalent > // y is bound by value, array by reference > [&, $y]($x) => $array[] = $x + $y > [=, &$array]($x) => $array[] = $x + $y > > And of course it does have downsides: > > - Symbol soup (it uses a lot of symbols) > - A minor BC break. Empty arrays which are invoked as functions are > currently guaranteed to be errors at runtime and would have a new > valid meaning. Here's an example from inside an array literal: > > // error at runtime previously > [ []($x) => $x ] > // now an array with one item which is a closure that returns > its parameter > > Sara pointed out that we'd need to keep a leading `=` or `&` in the > array to disambiguate from our array closure form. > > Overall I'd prefer 1 or 5. What do you guys think? > > > [1]: I'm pretty sure it can be done but until it's done I can't say > so confidently because sometimes there are things lurking in our > grammar I forget about. >
As I said in the old thread, option 5 with ==> instead of => might be an option. I think that would mitigate the minor BC break. r//Björn

Levi Morrison

9 years ago
On Tue, May 30, 2017 at 12:16 PM, Björn Larsson <bjorn.x.larsson@telia.com> wrote:
> Den 2017-05-30 kl. 19:58, skrev Levi Morrison: >> >> Internals, >> >> The previous discussion thread has died down significantly and so I'd >> like to start a new one to refocus. This message has some redundant >> information by design so people don't have to reference the other >> thread so much. >> >> Based on the discussion there are a few different syntax choices >> people liked. Overall it's a feature that people seem to want but >> everyone seems to prefer a different syntax choice. >> >> 1. fn(params) => expr >> 2. function(params) => expr >> >> 3. (params) ==> expr >> 4. (params) => expr >> >> Note that 3 and 4 require a more powerful grammar and parser and that >> 4 has ambiguities. I think we can work around them by rules -- only >> mentioning it because its popular because of JavaScript and do not >> prefer this at all. >> >> Note that 1 requires a new keyword. >> >> Option 2 looks the best from that perspective but is by far the >> longest; remember people are partially interested in this feature >> because they want shorter closures which this doesn't really help. >> >> This is why everyone is so divisive. All options have drawbacks. >> Additionally some people don't like binding by value and would prefer >> ref, and others really would be against by-ref. >> >> Which brings me to an option I don't think was ever discussed on list: >> >> 5. >> [](params) => expr // binds no values >> [=](params) => expr // binds by value >> [&](params) => expr // binds by reference >> >> It has quite a few good qualities: >> >> - No new keywords >> - Can choose between reference and value >> - Concise >> - Has precedence in C++, a major language >> - Can be done in our existing grammar and parser[1] >> - Can be extended to allow explicit binding of variables: >> // all equivalent >> // y is bound by value, array by reference >> [&, $y]($x) => $array[] = $x + $y >> [=, &$array]($x) => $array[] = $x + $y >> >> And of course it does have downsides: >> >> - Symbol soup (it uses a lot of symbols) >> - A minor BC break. Empty arrays which are invoked as functions are >> currently guaranteed to be errors at runtime and would have a new >> valid meaning. Here's an example from inside an array literal: >> >> // error at runtime previously >> [ []($x) => $x ] >> // now an array with one item which is a closure that returns >> its parameter >> >> Sara pointed out that we'd need to keep a leading `=` or `&` in the >> array to disambiguate from our array closure form. >> >> Overall I'd prefer 1 or 5. What do you guys think? >> >> >> [1]: I'm pretty sure it can be done but until it's done I can't say >> so confidently because sometimes there are things lurking in our >> grammar I forget about. >> > As I said in the old thread, option 5 with ==> instead of => might > be an option. I think that would mitigate the minor BC break. > > r//Björn
The compatibility issue is with `[](params)` is that it is currently an empty array literal that will be invoked; this is guaranteed to be an error at runtime so it is unlikely to cause much trouble. A trailing `==>` would not help here.

Nikita Popov

9 years ago
On Tue, May 30, 2017 at 8:24 PM, Levi Morrison <levim@php.net> wrote:
> On Tue, May 30, 2017 at 12:16 PM, Björn Larsson > <bjorn.x.larsson@telia.com> wrote: > > Den 2017-05-30 kl. 19:58, skrev Levi Morrison: > >> > >> Internals, > >> > >> The previous discussion thread has died down significantly and so I'd > >> like to start a new one to refocus. This message has some redundant > >> information by design so people don't have to reference the other > >> thread so much. > >> > >> Based on the discussion there are a few different syntax choices > >> people liked. Overall it's a feature that people seem to want but > >> everyone seems to prefer a different syntax choice. > >> > >> 1. fn(params) => expr > >> 2. function(params) => expr > >> > >> 3. (params) ==> expr > >> 4. (params) => expr > >> > >> Note that 3 and 4 require a more powerful grammar and parser and that > >> 4 has ambiguities. I think we can work around them by rules -- only > >> mentioning it because its popular because of JavaScript and do not > >> prefer this at all. > >> > >> Note that 1 requires a new keyword. > >> > >> Option 2 looks the best from that perspective but is by far the > >> longest; remember people are partially interested in this feature > >> because they want shorter closures which this doesn't really help. > >> > >> This is why everyone is so divisive. All options have drawbacks. > >> Additionally some people don't like binding by value and would prefer > >> ref, and others really would be against by-ref. > >> > >> Which brings me to an option I don't think was ever discussed on list: > >> > >> 5. > >> [](params) => expr // binds no values > >> [=](params) => expr // binds by value > >> [&](params) => expr // binds by reference > >> > >> It has quite a few good qualities: > >> > >> - No new keywords > >> - Can choose between reference and value > >> - Concise > >> - Has precedence in C++, a major language > >> - Can be done in our existing grammar and parser[1] > >> - Can be extended to allow explicit binding of variables: > >> // all equivalent > >> // y is bound by value, array by reference > >> [&, $y]($x) => $array[] = $x + $y > >> [=, &$array]($x) => $array[] = $x + $y > >> > >> And of course it does have downsides: > >> > >> - Symbol soup (it uses a lot of symbols) > >> - A minor BC break. Empty arrays which are invoked as functions are > >> currently guaranteed to be errors at runtime and would have a new > >> valid meaning. Here's an example from inside an array literal: > >> > >> // error at runtime previously > >> [ []($x) => $x ] > >> // now an array with one item which is a closure that returns > >> its parameter > >> > >> Sara pointed out that we'd need to keep a leading `=` or `&` in the > >> array to disambiguate from our array closure form. > >> > >> Overall I'd prefer 1 or 5. What do you guys think? > >> > >> > >> [1]: I'm pretty sure it can be done but until it's done I can't say > >> so confidently because sometimes there are things lurking in our > >> grammar I forget about. > >> > > As I said in the old thread, option 5 with ==> instead of => might > > be an option. I think that would mitigate the minor BC break. > > > > r//Björn > > The compatibility issue is with `[](params)` is that it is currently > an empty array literal that will be invoked; this is guaranteed to be > an error at runtime so it is unlikely to cause much trouble. A > trailing `==>` would not help here. >
You mentioned ability to explicitly specify binding as a possible extension. However [$var1, $var2]() is not necessarily failing right now, it may be a valid array callable. Nikita

Levi Morrison

9 years ago
On Tue, May 30, 2017 at 12:36 PM, Nikita Popov <nikita.ppv@gmail.com> wrote:
> On Tue, May 30, 2017 at 8:24 PM, Levi Morrison <levim@php.net> wrote: >> >> On Tue, May 30, 2017 at 12:16 PM, Björn Larsson >> <bjorn.x.larsson@telia.com> wrote: >> > Den 2017-05-30 kl. 19:58, skrev Levi Morrison: >> >> >> >> Internals, >> >> >> >> The previous discussion thread has died down significantly and so I'd >> >> like to start a new one to refocus. This message has some redundant >> >> information by design so people don't have to reference the other >> >> thread so much. >> >> >> >> Based on the discussion there are a few different syntax choices >> >> people liked. Overall it's a feature that people seem to want but >> >> everyone seems to prefer a different syntax choice. >> >> >> >> 1. fn(params) => expr >> >> 2. function(params) => expr >> >> >> >> 3. (params) ==> expr >> >> 4. (params) => expr >> >> >> >> Note that 3 and 4 require a more powerful grammar and parser and that >> >> 4 has ambiguities. I think we can work around them by rules -- only >> >> mentioning it because its popular because of JavaScript and do not >> >> prefer this at all. >> >> >> >> Note that 1 requires a new keyword. >> >> >> >> Option 2 looks the best from that perspective but is by far the >> >> longest; remember people are partially interested in this feature >> >> because they want shorter closures which this doesn't really help. >> >> >> >> This is why everyone is so divisive. All options have drawbacks. >> >> Additionally some people don't like binding by value and would prefer >> >> ref, and others really would be against by-ref. >> >> >> >> Which brings me to an option I don't think was ever discussed on list: >> >> >> >> 5. >> >> [](params) => expr // binds no values >> >> [=](params) => expr // binds by value >> >> [&](params) => expr // binds by reference >> >> >> >> It has quite a few good qualities: >> >> >> >> - No new keywords >> >> - Can choose between reference and value >> >> - Concise >> >> - Has precedence in C++, a major language >> >> - Can be done in our existing grammar and parser[1] >> >> - Can be extended to allow explicit binding of variables: >> >> // all equivalent >> >> // y is bound by value, array by reference >> >> [&, $y]($x) => $array[] = $x + $y >> >> [=, &$array]($x) => $array[] = $x + $y >> >> >> >> And of course it does have downsides: >> >> >> >> - Symbol soup (it uses a lot of symbols) >> >> - A minor BC break. Empty arrays which are invoked as functions are >> >> currently guaranteed to be errors at runtime and would have a new >> >> valid meaning. Here's an example from inside an array literal: >> >> >> >> // error at runtime previously >> >> [ []($x) => $x ] >> >> // now an array with one item which is a closure that returns >> >> its parameter >> >> >> >> Sara pointed out that we'd need to keep a leading `=` or `&` in the >> >> array to disambiguate from our array closure form. >> >> >> >> Overall I'd prefer 1 or 5. What do you guys think? >> >> >> >> >> >> [1]: I'm pretty sure it can be done but until it's done I can't say >> >> so confidently because sometimes there are things lurking in our >> >> grammar I forget about. >> >> >> > As I said in the old thread, option 5 with ==> instead of => might >> > be an option. I think that would mitigate the minor BC break. >> > >> > r//Björn >> >> The compatibility issue is with `[](params)` is that it is currently >> an empty array literal that will be invoked; this is guaranteed to be >> an error at runtime so it is unlikely to cause much trouble. A >> trailing `==>` would not help here. > > > You mentioned ability to explicitly specify binding as a possible extension. > However > > [$var1, $var2]() > > is not necessarily failing right now, it may be a valid array callable. > > Nikita
As already mentioned we must maintain a leading `=` or `&`: [=, $var1, $var2]() [=, $var1, $var2]() Sorry if that was unclear.

Levi Morrison

9 years ago
>> You mentioned ability to explicitly specify binding as a possible extension. >> However >> >> [$var1, $var2]() >> >> is not necessarily failing right now, it may be a valid array callable. >> >> Nikita > > As already mentioned we must maintain a leading `=` or `&`: > > [=, $var1, $var2]() > [=, $var1, $var2]() > > Sorry if that was unclear.
Oops, forgot to change the bottom line: [=, $var1, $var2]() [&, $var1, $var2]() The first line means "bind any implicit usages of variables by value, and also bind $var1 and $var2 by value". The second line means "bind any implicit usages of variables by reference, and bind $var1 and $var2 by value". This exists in C++ but C++ allows you to drop the leading `=` or `&`. We cannot, for precisely the reason you mentioned.

Björn Larsson

9 years ago
Den 2017-05-30 kl. 20:24, skrev Levi Morrison:
> On Tue, May 30, 2017 at 12:16 PM, Björn Larsson > <bjorn.x.larsson@telia.com> wrote: >> Den 2017-05-30 kl. 19:58, skrev Levi Morrison: >>> Internals, >>> >>> The previous discussion thread has died down significantly and so I'd >>> like to start a new one to refocus. This message has some redundant >>> information by design so people don't have to reference the other >>> thread so much. >>> >>> Based on the discussion there are a few different syntax choices >>> people liked. Overall it's a feature that people seem to want but >>> everyone seems to prefer a different syntax choice. >>> >>> 1. fn(params) => expr >>> 2. function(params) => expr >>> >>> 3. (params) ==> expr >>> 4. (params) => expr >>> >>> Note that 3 and 4 require a more powerful grammar and parser and that >>> 4 has ambiguities. I think we can work around them by rules -- only >>> mentioning it because its popular because of JavaScript and do not >>> prefer this at all. >>> >>> Note that 1 requires a new keyword. >>> >>> Option 2 looks the best from that perspective but is by far the >>> longest; remember people are partially interested in this feature >>> because they want shorter closures which this doesn't really help. >>> >>> This is why everyone is so divisive. All options have drawbacks. >>> Additionally some people don't like binding by value and would prefer >>> ref, and others really would be against by-ref. >>> >>> Which brings me to an option I don't think was ever discussed on list: >>> >>> 5. >>> [](params) => expr // binds no values >>> [=](params) => expr // binds by value >>> [&](params) => expr // binds by reference >>> >>> It has quite a few good qualities: >>> >>> - No new keywords >>> - Can choose between reference and value >>> - Concise >>> - Has precedence in C++, a major language >>> - Can be done in our existing grammar and parser[1] >>> - Can be extended to allow explicit binding of variables: >>> // all equivalent >>> // y is bound by value, array by reference >>> [&, $y]($x) => $array[] = $x + $y >>> [=, &$array]($x) => $array[] = $x + $y >>> >>> And of course it does have downsides: >>> >>> - Symbol soup (it uses a lot of symbols) >>> - A minor BC break. Empty arrays which are invoked as functions are >>> currently guaranteed to be errors at runtime and would have a new >>> valid meaning. Here's an example from inside an array literal: >>> >>> // error at runtime previously >>> [ []($x) => $x ] >>> // now an array with one item which is a closure that returns >>> its parameter >>> >>> Sara pointed out that we'd need to keep a leading `=` or `&` in the >>> array to disambiguate from our array closure form. >>> >>> Overall I'd prefer 1 or 5. What do you guys think? >>> >>> >>> [1]: I'm pretty sure it can be done but until it's done I can't say >>> so confidently because sometimes there are things lurking in our >>> grammar I forget about. >>> >> As I said in the old thread, option 5 with ==> instead of => might >> be an option. I think that would mitigate the minor BC break. >> >> r//Björn > The compatibility issue is with `[](params)` is that it is currently > an empty array literal that will be invoked; this is guaranteed to be > an error at runtime so it is unlikely to cause much trouble. A > trailing `==>` would not help here.
Ok, but how about having ==> to improve readability and make it less ambiguous & quicker to read the code. Also enable the syntax: - (params) ==> expr // binds no values. r//Björn

Derick Rethans

9 years ago
On Tue, 30 May 2017, Levi Morrison wrote:
> Internals, > > The previous discussion thread has died down significantly and so I'd > like to start a new one to refocus. This message has some redundant > information by design so people don't have to reference the other > thread so much. > > Based on the discussion there are a few different syntax choices > people liked. Overall it's a feature that people seem to want but > everyone seems to prefer a different syntax choice. > > 1. fn(params) => expr > 2. function(params) => expr > > 3. (params) ==> expr > 4. (params) => expr > > Note that 3 and 4 require a more powerful grammar and parser and that > 4 has ambiguities. I think we can work around them by rules -- only > mentioning it because its popular because of JavaScript and do not > prefer this at all. > > Note that 1 requires a new keyword. > > Option 2 looks the best from that perspective but is by far the > longest; remember people are partially interested in this feature > because they want shorter closures which this doesn't really help. > > This is why everyone is so divisive. All options have drawbacks. > Additionally some people don't like binding by value and would prefer > ref, and others really would be against by-ref. > > Which brings me to an option I don't think was ever discussed on list: > > 5. > [](params) => expr // binds no values > [=](params) => expr // binds by value > [&](params) => expr // binds by reference > > It has quite a few good qualities: > > - No new keywords > - Can choose between reference and value > - Concise > - Has precedence in C++, a major language > - Can be done in our existing grammar and parser[1] > - Can be extended to allow explicit binding of variables: > // all equivalent > // y is bound by value, array by reference > [&, $y]($x) => $array[] = $x + $y > [=, &$array]($x) => $array[] = $x + $y > > And of course it does have downsides: > > - Symbol soup (it uses a lot of symbols) > - A minor BC break. Empty arrays which are invoked as functions are > currently guaranteed to be errors at runtime and would have a new > valid meaning. Here's an example from inside an array literal: > > // error at runtime previously > [ []($x) => $x ] > // now an array with one item which is a closure that returns > its parameter > > Sara pointed out that we'd need to keep a leading `=` or `&` in the > array to disambiguate from our array closure form. > > Overall I'd prefer 1 or 5. What do you guys think?
I think 5 is terrible from a readability point of view. As you said it: "symbol soup". For a similar reason, I would discount 1 as being too vague. And hence would prefer 2, but I'm not actually convinced about this feature at all. cheers, Derick
-- https://derickrethans.nl | https://xdebug.org | https://dram.io Like Xdebug? Consider a donation: https://xdebug.org/donate.php twitter: @derickr and @xdebug

Björn Larsson

9 years ago
Den 2017-05-30 kl. 21:40, skrev Derick Rethans:
> On Tue, 30 May 2017, Levi Morrison wrote: > >> Internals, >> >> The previous discussion thread has died down significantly and so I'd >> like to start a new one to refocus. This message has some redundant >> information by design so people don't have to reference the other >> thread so much. >> >> Based on the discussion there are a few different syntax choices >> people liked. Overall it's a feature that people seem to want but >> everyone seems to prefer a different syntax choice. >> >> 1. fn(params) => expr >> 2. function(params) => expr >> >> 3. (params) ==> expr >> 4. (params) => expr >> >> Note that 3 and 4 require a more powerful grammar and parser and that >> 4 has ambiguities. I think we can work around them by rules -- only >> mentioning it because its popular because of JavaScript and do not >> prefer this at all. >> >> Note that 1 requires a new keyword. >> >> Option 2 looks the best from that perspective but is by far the >> longest; remember people are partially interested in this feature >> because they want shorter closures which this doesn't really help. >> >> This is why everyone is so divisive. All options have drawbacks. >> Additionally some people don't like binding by value and would prefer >> ref, and others really would be against by-ref. >> >> Which brings me to an option I don't think was ever discussed on list: >> >> 5. >> [](params) => expr // binds no values >> [=](params) => expr // binds by value >> [&](params) => expr // binds by reference >> >> It has quite a few good qualities: >> >> - No new keywords >> - Can choose between reference and value >> - Concise >> - Has precedence in C++, a major language >> - Can be done in our existing grammar and parser[1] >> - Can be extended to allow explicit binding of variables: >> // all equivalent >> // y is bound by value, array by reference >> [&, $y]($x) => $array[] = $x + $y >> [=, &$array]($x) => $array[] = $x + $y >> >> And of course it does have downsides: >> >> - Symbol soup (it uses a lot of symbols) >> - A minor BC break. Empty arrays which are invoked as functions are >> currently guaranteed to be errors at runtime and would have a new >> valid meaning. Here's an example from inside an array literal: >> >> // error at runtime previously >> [ []($x) => $x ] >> // now an array with one item which is a closure that returns >> its parameter >> >> Sara pointed out that we'd need to keep a leading `=` or `&` in the >> array to disambiguate from our array closure form. >> >> Overall I'd prefer 1 or 5. What do you guys think? > I think 5 is terrible from a readability point of view. As you said it: > "symbol soup".
Do you think having ==> instead of => would make it less of a symbolic soup?
> > For a similar reason, I would discount 1 as being too vague. And hence > would prefer 2, but I'm not actually convinced about this feature at > all.
Well, maybe the option lambda(params) might be an alternative ;) When it comes to the need of this feature one could weigh in that languages like Javascript, Java, C# and HACK already have it. Hm... maybe worth checking how much this feature is used in e.g. HACK to see how large the need is. Cheers //Björn

Levi Morrison

9 years ago
On Tue, May 30, 2017 at 3:37 PM, Björn Larsson <bjorn.x.larsson@telia.com> wrote:
> Den 2017-05-30 kl. 21:40, skrev Derick Rethans: > >> On Tue, 30 May 2017, Levi Morrison wrote: >> >>> Internals, >>> >>> The previous discussion thread has died down significantly and so I'd >>> like to start a new one to refocus. This message has some redundant >>> information by design so people don't have to reference the other >>> thread so much. >>> >>> Based on the discussion there are a few different syntax choices >>> people liked. Overall it's a feature that people seem to want but >>> everyone seems to prefer a different syntax choice. >>> >>> 1. fn(params) => expr >>> 2. function(params) => expr >>> >>> 3. (params) ==> expr >>> 4. (params) => expr >>> >>> Note that 3 and 4 require a more powerful grammar and parser and that >>> 4 has ambiguities. I think we can work around them by rules -- only >>> mentioning it because its popular because of JavaScript and do not >>> prefer this at all. >>> >>> Note that 1 requires a new keyword. >>> >>> Option 2 looks the best from that perspective but is by far the >>> longest; remember people are partially interested in this feature >>> because they want shorter closures which this doesn't really help. >>> >>> This is why everyone is so divisive. All options have drawbacks. >>> Additionally some people don't like binding by value and would prefer >>> ref, and others really would be against by-ref. >>> >>> Which brings me to an option I don't think was ever discussed on list: >>> >>> 5. >>> [](params) => expr // binds no values >>> [=](params) => expr // binds by value >>> [&](params) => expr // binds by reference >>> >>> It has quite a few good qualities: >>> >>> - No new keywords >>> - Can choose between reference and value >>> - Concise >>> - Has precedence in C++, a major language >>> - Can be done in our existing grammar and parser[1] >>> - Can be extended to allow explicit binding of variables: >>> // all equivalent >>> // y is bound by value, array by reference >>> [&, $y]($x) => $array[] = $x + $y >>> [=, &$array]($x) => $array[] = $x + $y >>> >>> And of course it does have downsides: >>> >>> - Symbol soup (it uses a lot of symbols) >>> - A minor BC break. Empty arrays which are invoked as functions are >>> currently guaranteed to be errors at runtime and would have a new >>> valid meaning. Here's an example from inside an array literal: >>> >>> // error at runtime previously >>> [ []($x) => $x ] >>> // now an array with one item which is a closure that returns >>> its parameter >>> >>> Sara pointed out that we'd need to keep a leading `=` or `&` in the >>> array to disambiguate from our array closure form. >>> >>> Overall I'd prefer 1 or 5. What do you guys think? >> >> I think 5 is terrible from a readability point of view. As you said it: >> "symbol soup". > > Do you think having ==> instead of => would make it less of a > symbolic soup?
If something is already symbol soup how does adding another symbol make it less so?

Björn Larsson

9 years ago
Den 2017-05-31 kl. 00:26, skrev Levi Morrison:
> On Tue, May 30, 2017 at 3:37 PM, Björn Larsson > <bjorn.x.larsson@telia.com> wrote: >> Den 2017-05-30 kl. 21:40, skrev Derick Rethans: >> >>> On Tue, 30 May 2017, Levi Morrison wrote: >>> >>>> Internals, >>>> >>>> The previous discussion thread has died down significantly and so I'd >>>> like to start a new one to refocus. This message has some redundant >>>> information by design so people don't have to reference the other >>>> thread so much. >>>> >>>> Based on the discussion there are a few different syntax choices >>>> people liked. Overall it's a feature that people seem to want but >>>> everyone seems to prefer a different syntax choice. >>>> >>>> 1. fn(params) => expr >>>> 2. function(params) => expr >>>> >>>> 3. (params) ==> expr >>>> 4. (params) => expr >>>> >>>> Note that 3 and 4 require a more powerful grammar and parser and that >>>> 4 has ambiguities. I think we can work around them by rules -- only >>>> mentioning it because its popular because of JavaScript and do not >>>> prefer this at all. >>>> >>>> Note that 1 requires a new keyword. >>>> >>>> Option 2 looks the best from that perspective but is by far the >>>> longest; remember people are partially interested in this feature >>>> because they want shorter closures which this doesn't really help. >>>> >>>> This is why everyone is so divisive. All options have drawbacks. >>>> Additionally some people don't like binding by value and would prefer >>>> ref, and others really would be against by-ref. >>>> >>>> Which brings me to an option I don't think was ever discussed on list: >>>> >>>> 5. >>>> [](params) => expr // binds no values >>>> [=](params) => expr // binds by value >>>> [&](params) => expr // binds by reference >>>> >>>> It has quite a few good qualities: >>>> >>>> - No new keywords >>>> - Can choose between reference and value >>>> - Concise >>>> - Has precedence in C++, a major language >>>> - Can be done in our existing grammar and parser[1] >>>> - Can be extended to allow explicit binding of variables: >>>> // all equivalent >>>> // y is bound by value, array by reference >>>> [&, $y]($x) => $array[] = $x + $y >>>> [=, &$array]($x) => $array[] = $x + $y >>>> >>>> And of course it does have downsides: >>>> >>>> - Symbol soup (it uses a lot of symbols) >>>> - A minor BC break. Empty arrays which are invoked as functions are >>>> currently guaranteed to be errors at runtime and would have a new >>>> valid meaning. Here's an example from inside an array literal: >>>> >>>> // error at runtime previously >>>> [ []($x) => $x ] >>>> // now an array with one item which is a closure that returns >>>> its parameter >>>> >>>> Sara pointed out that we'd need to keep a leading `=` or `&` in the >>>> array to disambiguate from our array closure form. >>>> >>>> Overall I'd prefer 1 or 5. What do you guys think? >>> I think 5 is terrible from a readability point of view. As you said it: >>> "symbol soup". >> Do you think having ==> instead of => would make it less of a >> symbolic soup? > If something is already symbol soup how does adding another symbol > make it less so? >
For me it was about using a symbol that is not used for other things like arrays. Kind of a new ingredience to the soup ;-) Not sure at all about the syntax, but going from Sara's example earlier. 1. [[]($x)=> $x] a bit similar to [($x)=> $x] vs 2. [[]($x)==> $x] less similar to [($x)=> $x] 2 has in my eyes less soup factor... Cheers //Björn

Rowan Collins

9 years ago
On 30 May 2017 18:58:14 BST, Levi Morrison <levim@php.net> wrote:
>Internals, > >The previous discussion thread has died down significantly and so I'd >like to start a new one to refocus. This message has some redundant >information by design so people don't have to reference the other >thread so much. > >Based on the discussion there are a few different syntax choices >people liked. Overall it's a feature that people seem to want but >everyone seems to prefer a different syntax choice.
I was just pondering alternative approaches to stop the => token being ambiguous, and wondered if surrounding the whole expression with braces could work: { => $bound * 2 } { $a, $b => $a * $b } I believe this eliminates the ambiguity with array notation, and is more concise than pretty much every alternative. I'm my opinion, grouping the arguments and body would make it more readable in context, as well. The only potential difficulty with parsing would be that this would technically be valid: if ( $test ) { $a => $a * 5 }; Because it means this: if ( $test ) { function ($a) { return $a * 5; }; } It's not ambiguous, but I don't know if this and similar constructs would cause problems with backtracking in the parser. Worst case, they could probably be defined as illegal, since it's pretty hard to construct a use case for such a thing. Regards,
-- Rowan Collins [IMSoP]

Levi Morrison

9 years ago
On Wed, May 31, 2017 at 7:36 AM, Rowan Collins <rowan.collins@gmail.com> wrote:
> On 30 May 2017 18:58:14 BST, Levi Morrison <levim@php.net> wrote: >>Internals, >> >>The previous discussion thread has died down significantly and so I'd >>like to start a new one to refocus. This message has some redundant >>information by design so people don't have to reference the other >>thread so much. >> >>Based on the discussion there are a few different syntax choices >>people liked. Overall it's a feature that people seem to want but >>everyone seems to prefer a different syntax choice. > > I was just pondering alternative approaches to stop the => token being ambiguous, and wondered if surrounding the whole expression with braces could work: > > { => $bound * 2 } > { $a, $b => $a * $b } > > I believe this eliminates the ambiguity with array notation, and is more concise than pretty much every alternative. I'm my opinion, grouping the arguments and body would make it more readable in context, as well.
This does not work. We permit expressions as statements and we also allow empty blocks: { $a = $foo; } These will conflict in the grammar.

Rowan Collins

9 years ago
On 31 May 2017 14:48:03 BST, Levi Morrison <levim@php.net> wrote:
>On Wed, May 31, 2017 at 7:36 AM, Rowan Collins ><rowan.collins@gmail.com> wrote: >> I was just pondering alternative approaches to stop the => token >being ambiguous, and wondered if surrounding the whole expression with >braces could work: >> >> { => $bound * 2 } >> { $a, $b => $a * $b } > >This does not work. We permit expressions as statements and we also >allow empty blocks: > > { > $a = $foo; > } > >These will conflict in the grammar.
Yeah, I wondered if that would be the case, but don't know enough about how parsers work to be sure one way or the other. It's not ambiguous, because the => wouldn't be legal there, but I guess it's "too late" by the time that token is reached. :( Regards,
-- Rowan Collins [IMSoP]

Ilija Tovilo

9 years ago
My preferences: 1, 3, 4, 5, (big void),  2. I actually like 4 the most but I get that that might not be practical if it leads to unexpected behaviour. I can’t think of a scenario where capturing by reference would be helpful in a single line closure. 5 just adds additional complexity with no additional benefit IMHO. Also, in response to Rowan, a Ruby-style syntax should be possible though: {|param| expr} Only caveat is that the || would be required if there are no parameters: {|| expr} Levi has mentioned this one before. You could even omit the braces here. Ilija On 30 May 2017, 19:58 +0200, Levi Morrison <levim@php.net>, wrote:

Levi Morrison

9 years ago
> I can’t think of a scenario where capturing by reference would be helpful in > a single line closure.
function($item) use($array) { return $array[] = $item; } It's actually one of the first closures I discovered in the wild when looking for closures that would be candidates for the short form.

Ilija Tovilo

9 years ago
I think it’s worth noting that the people most excited about arrow functions are probably the ones with a more functional approach. Those kinds of side effects are usually avoided. I also have nothing against capturing by reference. Given the last example: fn($item) => $array[] = $item All you have to do is glance a few characters to the left to see that $array is not a parameter and thus must be captured. And again, since it’s pretty obvious to see if you’re mutating the variable (spot the equal sign) this shouldn’t cause too many surprises. Only scenario I can think of is passing it to another function as a reference. But then again, no one ever complains about that in other languages. Ilija On 31 May 2017, 23:11 +0200, Levi Morrison <levim@php.net>, wrote:

Theodore Brown

9 years ago
On Tuesday, May 30, 2017 at 12:58 PM, Levi Morrison wrote:
> Based on the discussion there are a few different syntax choices > people liked. Overall it's a feature that people seem to want but > everyone seems to prefer a different syntax choice. > > 1. fn(params) => expr > 2. function(params) => expr > 3. (params) ==> expr > 4. (params) => expr > 5. > [](params) => expr // binds no values > [=](params) => expr // binds by value > [&](params) => expr // binds by reference
As a userland developer, I've been waiting/hoping for short arrow functions for a long time! Option 3 seems like the most obvious choice, since that's the same syntax Hack uses. Would it be very difficult to implement the parser changes necessary for this syntax? Or is there some other downside to a more powerful grammar/parser (e.g. worse performance)? If option 3 isn't viable, my next preference would be option 1. Presumably the drawback of a new symbol is that it might break existing code using `fn` as the name of a class or function. However, using a new symbol would arguably enable more readable code than the other options. Option 2 is not only lengthy, but it also could be confusing since it reuses the `function` symbol for something that isn't a normal function. Option 5 seems overly complex and hard to read. Whether option 1, 2, or 3 is used, to me it seems that capturing by reference would be the most useful and intuitive behavior. It's intuitive since implicit capture makes it feel like all the captured variables are in the same scope.

Björn Larsson

9 years ago
Den 2017-06-01 kl. 18:58, skrev Theodore Brown:
> On Tuesday, May 30, 2017 at 12:58 PM, Levi Morrison wrote: > >> Based on the discussion there are a few different syntax choices >> people liked. Overall it's a feature that people seem to want but >> everyone seems to prefer a different syntax choice. >> >> 1. fn(params) => expr >> 2. function(params) => expr >> 3. (params) ==> expr >> 4. (params) => expr >> 5. >> [](params) => expr // binds no values >> [=](params) => expr // binds by value >> [&](params) => expr // binds by reference > As a userland developer, I've been waiting/hoping for short arrow > functions for a long time! > > Option 3 seems like the most obvious choice, since that's the > same syntax Hack uses. Would it be very difficult to implement the > parser changes necessary for this syntax? Or is there some other > downside to a more powerful grammar/parser (e.g. worse performance)? > > If option 3 isn't viable, my next preference would be option 1. > Presumably the drawback of a new symbol is that it might break > existing code using `fn` as the name of a class or function. > However, using a new symbol would arguably enable more readable > code than the other options. > > Option 2 is not only lengthy, but it also could be confusing > since it reuses the `function` symbol for something that isn't > a normal function. > > Option 5 seems overly complex and hard to read. > > Whether option 1, 2, or 3 is used, to me it seems that capturing by > reference would be the most useful and intuitive behavior. It's > intuitive since implicit capture makes it feel like all the captured > variables are in the same scope.
As a user land developer, option 3 is also my favourite followed by 5 and last 1. However, for option 5 I would prefer ==> syntax and for option 1 I would prefer lambda as a keyword instead of fn. One thought that struck me, would option 3 be possible to extend also including option 5 either as a voting option or in a future RFC? And yes, arrow functions is much welcome! r//Björn

Rasmus Schultz

9 years ago
Of the proposed options, I'd prefer the double fat-arrow ==> However, I remain of the opinion that all of those syntaxes are work-arounds to ambiguity concerns for cases that likely don't actually occur in real-world codebases. I don't understand the motivation to design or optimize based on some theoretical concerns - I'd strongly prefer we do the obvious thing, which, as I see it, would be to do what most languages do, e.g. the familiar fat arrow => syntax. If we're going to provide a closure feature that works more like what you'd typically find in other languages, we should try to also make it look like it does in most other languages. It was said of the generics syntax that I proposed that it would have ambiguity issues, that it would be impossible (or very difficult) to implement, but someone actually went an implemented it. I'm generally a bit skeptical of people who cry "impossible" before giving it their best effort. Inventing unfamiliar syntax for familiar features should be a painful last resort, if there is no other choice. Just my opinion. I'd love to have this feature, but I'd prefer we don't introduce anymore "muck" if it's at all avoidable. On Mon, Jun 5, 2017 at 3:10 PM, Björn Larsson <bjorn.x.larsson@telia.com> wrote:

Larry Garfield

9 years ago
On 06/05/2017 09:19 AM, Rasmus Schultz wrote:
> Of the proposed options, I'd prefer the double fat-arrow ==> > > However, I remain of the opinion that all of those syntaxes are > work-arounds to ambiguity concerns for cases that likely don't actually > occur in real-world codebases. > > I don't understand the motivation to design or optimize based on some > theoretical concerns - I'd strongly prefer we do the obvious thing, which, > as I see it, would be to do what most languages do, e.g. the familiar fat > arrow => syntax. > > If we're going to provide a closure feature that works more like what you'd > typically find in other languages, we should try to also make it look like > it does in most other languages. > > It was said of the generics syntax that I proposed that it would have > ambiguity issues, that it would be impossible (or very difficult) to > implement, but someone actually went an implemented it. I'm generally a bit > skeptical of people who cry "impossible" before giving it their best effort. > > Inventing unfamiliar syntax for familiar features should be a painful last > resort, if there is no other choice. > > Just my opinion. > > I'd love to have this feature, but I'd prefer we don't introduce anymore > "muck" if it's at all avoidable. > > > On Mon, Jun 5, 2017 at 3:10 PM, Björn Larsson <bjorn.x.larsson@telia.com> > wrote: > >> Den 2017-06-01 kl. 18:58, skrev Theodore Brown: >> >> On Tuesday, May 30, 2017 at 12:58 PM, Levi Morrison wrote: >>> Based on the discussion there are a few different syntax choices >>>> people liked. Overall it's a feature that people seem to want but >>>> everyone seems to prefer a different syntax choice. >>>> >>>> 1. fn(params) => expr >>>> 2. function(params) => expr >>>> 3. (params) ==> expr >>>> 4. (params) => expr >>>> 5. >>>> [](params) => expr // binds no values >>>> [=](params) => expr // binds by value >>>> [&](params) => expr // binds by reference >>>>
3 > 4 > 1. 2 is not even worth considering and I'd almost prefer not having arrow functions if their syntax is going to be that self-defeating. I also see no reason to include both by-value and by-reference binding Arrow functions are for trivially simple cases where the extra ceremony of an anonymous function is a waste. If you need to do something non-trivial, use a full-on anonymous function as we already support. I want to reiterate that, from a user-POV, arrow functions are barely functions. It's a case for applying an expression to a set. In most cases I don't "think about it" as a function in the first place. $y = 2; array_map($arr, ($x)=> $x*$y); While I know that implementation-wise $x * 2 gets wrapped into a function, that's not really how I'm mentally thinking about it. I'm thinking of it more like a single line in a foreach. In my head, it's an expression, not a function. If I needed to be "thinking about it like a function", I'd use a more function-esque syntax. The extra complication of multiple binding styles to think about are just that: extra complication. If I care, then I should be using an anonymous function whose use() syntax already lets me control that case. I wonder if "Arrow functions" is even a misleading name for the feature, in terms of how it should be used. --Larry Garfield

Fleshgrinder

9 years ago
On 6/5/2017 6:17 PM, Larry Garfield wrote:
> 3 > 4 > 1. > > 2 is not even worth considering and I'd almost prefer not having arrow > functions if their syntax is going to be that self-defeating. > > I also see no reason to include both by-value and by-reference binding > Arrow functions are for trivially simple cases where the extra ceremony > of an anonymous function is a waste. If you need to do something > non-trivial, use a full-on anonymous function as we already support. > > I want to reiterate that, from a user-POV, arrow functions are barely > functions. It's a case for applying an expression to a set. In most > cases I don't "think about it" as a function in the first place. > > $y = 2; > array_map($arr, ($x)=> $x*$y); > > While I know that implementation-wise $x * 2 gets wrapped into a > function, that's not really how I'm mentally thinking about it. I'm > thinking of it more like a single line in a foreach. In my head, it's > an expression, not a function. If I needed to be "thinking about it > like a function", I'd use a more function-esque syntax. > > The extra complication of multiple binding styles to think about are > just that: extra complication. If I care, then I should be using an > anonymous function whose use() syntax already lets me control that case. > > I wonder if "Arrow functions" is even a misleading name for the feature, > in terms of how it should be used. > > --Larry Garfield >
I agree with Larry here. Another thing that would be great to have is a universal syntax that we can expand to cover methods at a later point too. Ceylon has that available everywhere, and it is nice for writing simple methods. final class SomeEnum { private $v; private __construct(string $v) => $this->v = $v; public static Foo() => new static('FOO'); public static Bar() => new static('BAR'); } Could someone explain me again what the problem with the simple fat-arrow and normal parenthesis is? Cannot find it anymore (too many messages in too many thread I guess). I would guess that it has to do with the arbitrary look-ahead that is required to check for the fat arrow before the lexer knows that this is a short closure and not some parenthesis that simply groups something. Wouldn't it be possible to go for the pipes then? I mean, pipes without an expression to the left are not valid right now, and they most probably will never be. Union types might require them, but they are not lonely there too. Hence: || 42 function () { return 42; } |$a, $b| $a + $b function () { return $a + $b; } References and use should be easy to add: |$a| |&$b| $b += $a function ($a) use (&$b) { return ($b += $a); } This syntax does not translate nicely to method though: public static Foo|| new static('FOO'); Looks kind 'a weird and now we have something on the lhs of the pipes that looks very much like a union type. We could still go for the fat arrow syntax here, even if the pipes are used for short closures. The two features are not the same after all.
-- Richard "Fleshgrinder" Fussenegger

Rowan Collins

9 years ago
On 5 June 2017 18:17:06 BST, Fleshgrinder <php@fleshgrinder.com> wrote:
>Could someone explain me again what the problem with the simple >fat-arrow and normal parenthesis is? Cannot find it anymore (too many >messages in too many thread I guess). I would guess that it has to do >with the arbitrary look-ahead that is required to check for the fat >arrow before the lexer knows that this is a short closure and not some >parenthesis that simply groups something.
I think it's not just a case of implementation problems, it's actually ambiguous with current syntax: $foo = array( ($x) => 42 ); Sure, those inner brackets are redundant, so it's not likely to break much actual code, but it's kind of weird to have this one case magically turn into a closure, when anything else you put in those brackets would just be used as the array key: $foo = array( f($x) => 42 ); $foo = array( ($x+1) => 42 ); $foo = array( (42) => $x ); $foo = array( (X) => 42 ); $foo = array( ($x) => 42 ); $foo = array( ("$x") => 42 ); Even if we could teach the parser to understand it, I'd personally be against it for the difficulty of *humans* parsing it. I find shorthand closures hard enough to read anyway, especially when people suggest things like ($x) => ($y) => $x * $y * $z; Regards,
-- Rowan Collins [IMSoP]

Fleshgrinder

9 years ago
On 6/5/2017 7:55 PM, Rowan Collins wrote:
> I think it's not just a case of implementation problems, it's actually ambiguous with current syntax: > > $foo = array( ($x) => 42 ); > > Sure, those inner brackets are redundant, so it's not likely to break much actual code, but it's kind of weird to have this one case magically turn into a closure, when anything else you put in those brackets would just be used as the array key: > > $foo = array( f($x) => 42 ); > $foo = array( ($x+1) => 42 ); > $foo = array( (42) => $x ); > $foo = array( (X) => 42 ); > $foo = array( ($x) => 42 ); > $foo = array( ("$x") => 42 ); > > Even if we could teach the parser to understand it, I'd personally be against it for the difficulty of *humans* parsing it. I find shorthand closures hard enough to read anyway, especially when people suggest things like ($x) => ($y) => $x * $y * $z; > > Regards, >
Ah thanks, yeah, that was the problem. At trivago we have such a super fancy ES6 code base where everything is done in a super cryptic syntax, so that absolutely nobody who is not used to reading this all day has a chance to understand a single thing. So, yeah, I completely agree with you on everything. That being said, they are handy if not overused, like so many features. :) The pipes should still be in the game. $foo = array( |$x| => 42 );
-- Richard "Fleshgrinder" Fussenegger

Björn Larsson

9 years ago
Den 2017-06-05 kl. 19:55, skrev Rowan Collins:
> On 5 June 2017 18:17:06 BST, Fleshgrinder <php@fleshgrinder.com> wrote: >> Could someone explain me again what the problem with the simple >> fat-arrow and normal parenthesis is? Cannot find it anymore (too many >> messages in too many thread I guess). I would guess that it has to do >> with the arbitrary look-ahead that is required to check for the fat >> arrow before the lexer knows that this is a short closure and not some >> parenthesis that simply groups something. > I think it's not just a case of implementation problems, it's actually ambiguous with current syntax: > > $foo = array( ($x) => 42 ); > > Sure, those inner brackets are redundant, so it's not likely to break much actual code, but it's kind of weird to have this one case magically turn into a closure, when anything else you put in those brackets would just be used as the array key: > > $foo = array( f($x) => 42 ); > $foo = array( ($x+1) => 42 ); > $foo = array( (42) => $x ); > $foo = array( (X) => 42 ); > $foo = array( ($x) => 42 ); > $foo = array( ("$x") => 42 ); > > Even if we could teach the parser to understand it, I'd personally be against it for the difficulty of *humans* parsing it. I find shorthand closures hard enough to read anyway, especially when people suggest things like ($x) => ($y) => $x * $y * $z; > > Regards, >
+1, think you nailed it here :) One of the reasons I prefer the ==> syntax. r//Björn

Rasmus Schultz

9 years ago
Ugh, you're right, that's totally unreadable... the => is far too ambiguous with array syntax, I agree. How about just a thin arrow? (params) -> expr If the parens around params were required, it's not ambiguous with the trailing -- operator, is it? $foo->bar(($baz) -> $baz + 1); Consistent use of parens around the params might make closures a bit easier to spot in the wild? On Mon, Jun 5, 2017 at 8:11 PM, Björn Larsson <bjorn.x.larsson@telia.com> wrote:

Fleshgrinder

9 years ago
On 6/5/2017 8:36 PM, Rasmus Schultz wrote:
> Ugh, you're right, that's totally unreadable... the => is far too ambiguous > with array syntax, I agree. > > How about just a thin arrow? > > (params) -> expr > > If the parens around params were required, it's not ambiguous with the > trailing -- operator, is it? > > $foo->bar(($baz) -> $baz + 1); > > Consistent use of parens around the params might make closures a bit easier > to spot in the wild? >
This would actually work with everything, me likes. () -> 42 ($a, $b) -> $a + $b ($a) (&$b) -> $b += $a public static Foo() -> new static('Foo'); It also avoid any association with <?= which prints, not returns, and any other assignment related thing.
-- Richard "Fleshgrinder" Fussenegger