[RFC][Discuss] Arrow Functions

php.internals

Levi Morrison

9 years ago
Bob Weinand and I are happy to announce that the [Arrow Functions][1] RFC is moving into the public discussion phase. We have been collaborating on this RFC for many months now and finally have a proposal we are happy to discuss in the open. Here is an example of an existing closure: function ($x) use ($arr) { return $arr[$x]; } This RFC proposes syntax and semantics to simplify this common usage to: fn($x) => $arr[$x] More details are in the RFC. The [implementation][2] currently has no known issues and is ready for you to download, build and test, which we encourage you to do. We look forward to a productive discussion period and are happy to answer questions. For historical purposes, the revision of this RFC is currently at [1485798604][3]. [1]: https://wiki.php.net/rfc/arrow_functions [2]: https://github.com/morrisonlevi/php-src/tree/arrow_functions [3]: https://wiki.php.net/rfc/arrow_functions?rev=1485798604

Niklas Keller

9 years ago
Levi Morrison <levim@php.net> schrieb am Mo., 30. Jan. 2017, 18:55:
> Bob Weinand and I are happy to announce that the [Arrow Functions][1] > RFC is moving into the public discussion phase. We have been > collaborating on this RFC for many months now and finally have a > proposal we are happy to discuss in the open. > > Here is an example of an existing closure: > > function ($x) use ($arr) { > return $arr[$x]; > } > > This RFC proposes syntax and semantics to simplify this common usage to: > > fn($x) => $arr[$x] > > More details are in the RFC. The [implementation][2] currently has no > known issues and is ready for you to download, build and test, which > we encourage you to do. >
https://3v4l.org has a feature branch for arrow functions, you can find it in the preview select box for playing around and in the RFC tab after a full execution. We look forward to a productive discussion period and are happy to

Guy Marriott

9 years ago
On Tue, Jan 31, 2017 at 7:42 AM, Niklas Keller <me@kelunik.com> wrote:
> Levi Morrison <levim@php.net> schrieb am Mo., 30. Jan. 2017, 18:55: > > > Bob Weinand and I are happy to announce that the [Arrow Functions][1] > > RFC is moving into the public discussion phase. We have been > > collaborating on this RFC for many months now and finally have a > > proposal we are happy to discuss in the open. > > > > Here is an example of an existing closure: > > > > function ($x) use ($arr) { > > return $arr[$x]; > > } > > > > This RFC proposes syntax and semantics to simplify this common usage to: > > > > fn($x) => $arr[$x] > > > > More details are in the RFC. The [implementation][2] currently has no > > known issues and is ready for you to download, build and test, which > > we encourage you to do. > > > > https://3v4l.org has a feature branch for arrow functions, you can find > it > in the preview select box for playing around and in the RFC tab after a > full execution. > > We look forward to a productive discussion period and are happy to > > answer questions. > > > > For historical purposes, the revision of this RFC is currently at > > [1485798604][3]. > > > > [1]: https://wiki.php.net/rfc/arrow_functions > > [2]: https://github.com/morrisonlevi/php-src/tree/arrow_functions > > [3]: https://wiki.php.net/rfc/arrow_functions?rev=1485798604 > > > > -- > > PHP Internals - PHP Runtime Development Mailing List > > To unsubscribe, visit: http://www.php.net/unsub.php > > > > >
Looking good. Really excited for something like this in PHP. Just a heads up, the section in the introduction that refers to other languages having similar syntax still has a TODO in it. I agree that some references to other languages' implementations (ES6 comes to mind) would be a nice addition. Awesome work, Guy

Rowan Collins

9 years ago
On 30/01/2017 17:55, Levi Morrison wrote:
> Bob Weinand and I are happy to announce that the [Arrow Functions][1] > RFC is moving into the public discussion phase. We have been > collaborating on this RFC for many months now and finally have a > proposal we are happy to discuss in the open. > > [1]: https://wiki.php.net/rfc/arrow_functions
Firstly, I like this proposal a lot more than the previous, so thank you for working on this based on previous discussion. In particular, I'm glad to see it focused on single expressions with implicit return, as I think that's where it has most value. A few comments:
> ThisRFC does support type declarations for parameters and return types.
An example of the syntax for this would be good, particularly how the return type fits the syntax (which may conflict with my suggestion below).
> The implementation currently supports static closures, for example |static fn($x) => static::get($x)|.
I was initially confused by this paragraph, because I was unaware that static closures existed. I'm still not entirely sure *why* they exist, but for anyone else wondering, here's what they currently look like: http://php.net/manual/en/functions.anonymous.php#functions.anonymous-functions.static Finally, my personal preference is still for a syntax that encloses the whole definition somehow, and since we need the fn keyword anyway, I wonder about stretching the brackets around the whole definition, e.g. fn($x => $x * 2). Personally, I find this: ->reduce(fn($tmp, $v => $tmp + $v), 0) easier to mentally parse than this: ->reduce(fn($tmp, $v) => $tmp + $v, 0) because you only have to match brackets to see where the ", 0" belongs. I also think it would make combining closures clearer if they were nested rather than associative (I guess those used to reading Haskell will probably disagree with me): $complement = fn($f) => fn(... $args) => !$f(... $args) vs $complement = fn($f => fn(... $args => !$f(... $args))) Regards,
-- Rowan Collins [IMSoP]

Levi Morrison

9 years ago
On Mon, Jan 30, 2017 at 4:05 PM, Rowan Collins <rowan.collins@gmail.com> wrote:
> On 30/01/2017 17:55, Levi Morrison wrote: >> >> Bob Weinand and I are happy to announce that the [Arrow Functions][1] >> RFC is moving into the public discussion phase. We have been >> collaborating on this RFC for many months now and finally have a >> proposal we are happy to discuss in the open. >> >> [1]: https://wiki.php.net/rfc/arrow_functions > > > Firstly, I like this proposal a lot more than the previous, so thank you for > working on this based on previous discussion. In particular, I'm glad to see > it focused on single expressions with implicit return, as I think that's > where it has most value. > > A few comments: > >> ThisRFC does support type declarations for parameters and return types. > > > An example of the syntax for this would be good, particularly how the return > type fits the syntax (which may conflict with my suggestion below).
They go in the same places as regular functions. I'll update the RFC later with examples, but for now here is an example that takes an integer and returns it, which type declarations: fn (int $x): int => $x

Andrew Faulds

9 years ago
Hi Levi, Levi Morrison wrote:
> Here is an example of an existing closure: > > function ($x) use ($arr) { > return $arr[$x]; > } > > This RFC proposes syntax and semantics to simplify this common usage to: > > fn($x) => $arr[$x] >
Is it necessary to introduce a new keyword, fn? I think you'd get a similar benefit from: function($x) => $arr[$x] Likewise, is it necessary to restrict auto-capture to the => syntax? Couldn't we allow the following? function ($x) { return $arr[$x]; } That being said, I broadly support your goals.
-- Andrea Faulds https://ajf.me/

David Walker

9 years ago
On Mon, Jan 30, 2017 at 18:12 Andrea Faulds <ajf@ajf.me> wrote:
> Hi Levi, > > Levi Morrison wrote: > > Here is an example of an existing closure: > > > > function ($x) use ($arr) { > > return $arr[$x]; > > } > > > > This RFC proposes syntax and semantics to simplify this common usage to: > > > > fn($x) => $arr[$x] > > > > Is it necessary to introduce a new keyword, fn? > > I think you'd get a similar benefit from: > > function($x) => $arr[$x] > > Likewise, is it necessary to restrict auto-capture to the => syntax? > Couldn't we allow the following? > > function ($x) { > return $arr[$x]; > } >
This looks too similar to the current syntax, just ignoring the use() statement. I would add a concurance that => syntax is slightly awkward when used within an array element $a = [ 'func' => fn($x) => Class::method($x), ]; But I'm not overly certain of a different syntax to handle this. I would support expanding to function over fn, to make it more readable/keep the same reserved word. (Although not too certain to the complexity in the parser) Otherwise +1, I like this.
-- Dave

Andrew Faulds

9 years ago
Hi, David Walker wrote:
> On Mon, Jan 30, 2017 at 18:12 Andrea Faulds <ajf@ajf.me> wrote: > >> Is it necessary to introduce a new keyword, fn? >> >> I think you'd get a similar benefit from: >> >> function($x) => $arr[$x] >> >> Likewise, is it necessary to restrict auto-capture to the => syntax? >> Couldn't we allow the following? >> >> function ($x) { >> return $arr[$x]; >> } >> > > This looks too similar to the current syntax, just ignoring the use() > statement.
That's the idea. I'd prefer it if auto-capture was not restricted to single-expression functions (“arrow functions”). Though arrow functions make most sense with auto-capture, it doesn't need to be stricted to them. Thanks.
-- Andrea Faulds https://ajf.me/

Rowan Collins

9 years ago
On 31/01/2017 20:41, Andrea Faulds wrote:
> That's the idea. I'd prefer it if auto-capture was not restricted to > single-expression functions (“arrow functions”). Though arrow > functions make most sense with auto-capture, it doesn't need to be > stricted to them.
I respectfully disagree completely. Variable scope in PHP is very simple: inside a function, all variables are local to that function, and fetching them from anywhere else requires them to be enumerated with a specific keyword (e.g. global, static, use). The only exceptions are superglobals, the magic $this, and the odd mysterious materialisation like $http_response_header [1]. This means you can look at a function in isolation, no matter how it's declared, and see where every variable comes from. [1]: http://php.net/manual/en/reserved.variables.httpresponseheader.php Auto-capture with a full function body would be throwing out that principle. If a variable was read from before it was assigned to, that *might* mean it was unset, or it *might* mean it was imported from an outer scope. Changing the variable name in the outer scope might or might not require you to look for that variable name in the closure; adding a variable in the outer scope might *accidentally* change the behaviour of the closure; and so on. This is a lot easier in Javascript, although still a cause of confusion, because you can carry on until you hit "var" or "let". I understand C# also has auto-importing closures, but it too requires variables to be declared at some point. Initially, I was sceptical of auto-capture even with a single expression, but I've come round to its usefulness in short closures. Limiting it to a single expression ensures it's short, and means you can assume that *all* variables in the expression are imported other than those listed as parameters. Just an opinion, obviously, but I'm glad that the current proposal is limited to and optimised for this single expression case. Regards,
-- Rowan Collins [IMSoP]

Rasmus Lerdorf

9 years ago
On Tue, Jan 31, 2017 at 12:41 PM, Andrea Faulds <ajf@ajf.me> wrote:
> > That's the idea. I'd prefer it if auto-capture was not restricted to > single-expression functions (“arrow functions”). Though arrow functions > make most sense with auto-capture, it doesn't need to be stricted to them.
This goes against a very basic characteristic of PHP. The fact that you have to be explicit about globals and outer scope variables leaves you with a clean sandbox with no side effects inside your function. Changing that, especially after the fact for existing closures, is a complete non-starter and would subtly break a ton of code. The reason it is feasible to do this for single-expression closures in this short form syntax is that you don't typically need a local scope at all for these short closures and the syntax doesn't convey the idea that you would have a local scope. -Rasmus

Weirdan

9 years ago
On Wed, Feb 01, 2017 at 07:45:50AM -0800, Rasmus Lerdorf wrote:
> The reason it is feasible to do this for single-expression closures in this > short form syntax is that you don't typically need a local scope at all for > these short closures and the syntax doesn't convey the idea that you would > have a local scope.
Does this mean, in the context of this RFC, that short-form lambdas won't have their own scope though? I think it's not clear from RFC. Example: // would this create $ret in the outer scope assuming $ret was not // defined array_map(fn($elt) => $ret[] = $elt, [1]); var_dump($ret); // NULL or array(1) ? Current implementation (available on 3v4l.org) does create a local scope, but it should probably be explicitly stated in the RFC (and docs, should the RFC get accepted).

Rasmus Lerdorf

9 years ago
On Wed, Feb 1, 2017 at 8:05 AM, Bruce Weirdan <weirdan@gmail.com> wrote:
> On Wed, Feb 01, 2017 at 07:45:50AM -0800, Rasmus Lerdorf wrote: > > The reason it is feasible to do this for single-expression closures in > this > > short form syntax is that you don't typically need a local scope at all > for > > these short closures and the syntax doesn't convey the idea that you > would > > have a local scope. > > Does this mean, in the context of this RFC, that short-form lambdas > won't have their own scope though? I think it's not clear from RFC. > > Example: > // would this create $ret in the outer scope assuming $ret was not > // defined > array_map(fn($elt) => $ret[] = $elt, [1]); > var_dump($ret); // NULL or array(1) ? > > Current implementation (available on 3v4l.org) does create a local > scope, but it should probably be explicitly stated in the RFC (and > docs, should the RFC get accepted). >
I actually tend to think of these short-form lambdas as not having a local scope. That might sound a bit odd, but let me demonstrate: $f = fn() => print($var=1); $f(); echo $var; This should output 1 and then give a notice about $var being undefined on the echo. You probably think of $var as being a local scope variable here, but really it isn't. It is an imported variable that happened to not exist in the outer scope and it was assigned a value in the inner scope, but that assignment can't leak back out so it is still unassigned in the outer scope. I think of it this way, because if you do: $var = 3; $f = fn() => print(++$var); $f(); echo $var; You should see: 43 $var did not originate in the inner scope, it was imported from the outer scope by-value and reassigned. To me, automatic import precludes the notion of a local scope entirely. When a variable you use within the lambda isn't defined in the outer scope it acts exactly like a locally scoped variable, but it isn't, because defining it in the outer scope could potentially affect it depending on how it is used within the lambda. -Rasmus

Rowan Collins

9 years ago
On 01/02/2017 20:17, Rasmus Lerdorf wrote:
> You probably think of $var as being a local scope variable here, > but really it isn't. It is an imported variable that happened to not exist > in the outer scope and it was assigned a value in the inner scope, but that > assignment can't leak back out so it is still unassigned in the outer > scope.
I'm very confused by your terminology here. You definitely talk about two distinct scopes, "the inner scope" and "the outer scope", but then you assert that there is no "local scope". Surely the "inner scope" is "local" to the closure? In actual fact, it's local to *each invocation* of the closure, because the function is initialised with the original values each time. For instance: $a = 1; $fn = fn() => ++$a; $a = 42; echo $fn(), ' ', $fn, ' ', $fn(); This echoes 2 2 2, not 2 3 4, because the $a being incremented is new for each invocation. Nor does it echo 43 43 43, because it is only the value of $a that is captured, not its reference. I think the best description is this: the closure has its own scope, which is initialised on each invocation with a copy of another scope taken when it was defined. To go back to Bruce's question, the original statement was:
> you don't typically need a local scope at all for these short closures
The important point here is that within a single expression there is very little you can meaningfully do with a local scope other than read from it. It's generally a bad idea to alter the value of a variable and expect another part of the same expression to see the new value, because you can't always predict how the compiler will rewrite the expression (I think an example of this came up on the list a while back, but can't think how to search for it). So for most purposes you can consider all the automatically imported variables to be immutable values, which makes their scope much less relevant. Regards,
-- Rowan Collins [IMSoP]

Rasmus Lerdorf

9 years ago
On Wed, Feb 1, 2017 at 3:06 PM, Rowan Collins <rowan.collins@gmail.com> wrote:
> On 01/02/2017 20:17, Rasmus Lerdorf wrote: > >> You probably think of $var as being a local scope variable here, >> but really it isn't. It is an imported variable that happened to not exist >> in the outer scope and it was assigned a value in the inner scope, but >> that >> assignment can't leak back out so it is still unassigned in the outer >> scope. >> > > I'm very confused by your terminology here. You definitely talk about two > distinct scopes, "the inner scope" and "the outer scope", but then you > assert that there is no "local scope". Surely the "inner scope" is "local" > to the closure? > > In actual fact, it's local to *each invocation* of the closure, because > the function is initialised with the original values each time. For > instance: > > $a = 1; > $fn = fn() => ++$a; > $a = 42; > echo $fn(), ' ', $fn, ' ', $fn(); > > This echoes 2 2 2, not 2 3 4, because the $a being incremented is new for > each invocation. Nor does it echo 43 43 43, because it is only the value of > $a that is captured, not its reference. > > I think the best description is this: the closure has its own scope, which > is initialised on each invocation with a copy of another scope taken when > it was defined. > > > To go back to Bruce's question, the original statement was: > > you don't typically need a local scope at all for these short closures >> > > The important point here is that within a single expression there is very > little you can meaningfully do with a local scope other than read from it. > It's generally a bad idea to alter the value of a variable and expect > another part of the same expression to see the new value, because you can't > always predict how the compiler will rewrite the expression (I think an > example of this came up on the list a while back, but can't think how to > search for it). > > So for most purposes you can consider all the automatically imported > variables to be immutable values, which makes their scope much less > relevant.
It is mostly a semantic thing. Of course you have a local scope, but because of automatic import you don't have a clean local scope so it is not like the function-local scope people are used to. Like you said, it is a mostly immutable copy of the outer scope. But people need to understand that the immutability doesn't apply to class variables because there is no automatic clone done on outer scope objects. class C { static $var = 1; } $f = fn() => C::$var++; echo $f().$f().$f(); will output 123 and the value of C::$var would be 4 after this. -Rasmus

Stephen Reay

9 years ago
Hi Andrea, All,
> On 31 Jan 2017, at 08:12, Andrea Faulds <ajf@ajf.me> wrote: > > Is it necessary to introduce a new keyword, fn? > > I think you'd get a similar benefit from: > > function($x) => $arr[$x] > > Likewise, is it necessary to restrict auto-capture to the => syntax? Couldn't we allow the following? > > function ($x) { > return $arr[$x]; > } >
I agree that the `fn` keyword isn’t really necessary. I’ve never quite understood how arrow functions with implied returns etc are supposed to make for *more* readable code, but if they’re going to be part of the language please at least keep some consistency with regular closures. In the case that regular closures got auto-capture, would a `use($foo, $bar, $baz)` segment on a closure still be honoured (i.e. disable auto-capture), and would it have any impact (positive or negative) on performance/memory usage? After several years of JS closure ‘fun’ I kind of like that with PHP you only inherit the variables you explicitly `use()` in closures. Cheers Stephen

Marc Bennewitz

9 years ago
Am 31.01.2017 um 05:53 schrieb Stephen Reay:
> Hi Andrea, All, > >> On 31 Jan 2017, at 08:12, Andrea Faulds <ajf@ajf.me> wrote: >> >> Is it necessary to introduce a new keyword, fn? >> >> I think you'd get a similar benefit from: >> >> function($x) => $arr[$x] >> >> Likewise, is it necessary to restrict auto-capture to the => syntax? Couldn't we allow the following? >> >> function ($x) { >> return $arr[$x]; >> } >> > > I agree that the `fn` keyword isn’t really necessary. I’ve never quite understood how arrow functions with implied returns etc are supposed to make for *more* readable code, but if they’re going to be part of the language please at least keep some consistency with regular closures. > > In the case that regular closures got auto-capture, would a `use($foo, $bar, $baz)` segment on a closure still be honoured (i.e. disable auto-capture), and would it have any impact (positive or negative) on performance/memory usage? After several years of JS closure ‘fun’ I kind of like that with PHP you only inherit the variables you explicitly `use()` in closures.
I like the general idea, too. But with similar feelings for: - Introducing a second keyword for closures is confusing - and mor confusing if they are basically the same words - Also I like the "use" keyword you have to define your variables -> Would it be helpful to allow "function () use (*) {}" to inline all available variables? - Or based on Rowans idea to stretching the brackets but using the function keyword: function($x => $arr[$x]) Thanks Marc

Andrew Faulds

9 years ago
Hi Marc, Marc Bennewitz wrote:
> - Also I like the "use" keyword you have to define your variables > > -> Would it be helpful to allow "function () use (*) {}" to inline > all available variables?
I did think of that, but it's not as concise as not having to specify `use` at all. You could take the opposite approach and auto-capture by default, but permit `use ()` to capture nothing, alongside regular `use (...)` for explicit capture of variables. Thanks.
-- Andrea Faulds https://ajf.me/

Bob Weinand

9 years ago
> Am 31.01.2017 um 21:45 schrieb Andrea Faulds <ajf@ajf.me>: > > Hi Marc, > > Marc Bennewitz wrote: >> - Also I like the "use" keyword you have to define your variables >> >> -> Would it be helpful to allow "function () use (*) {}" to inline >> all available variables? > > I did think of that, but it's not as concise as not having to specify `use` at all. You could take the opposite approach and auto-capture by default, but permit `use ()` to capture nothing, alongside regular `use (...)` for explicit capture of variables. > > Thanks. > > -- > Andrea Faulds > https://ajf.me/
Hey Andrea, you realize that you are actually proposing quite a heavy BC break? Any code which uses the same variable than in parent scope and does not overwrite it before its first usage will break. E.g.: $foo = [1,2,3]; // more code working on foo doSomeAction(function($bar) { // waaah, $foo is now [1,2,3] instead of null foreach ($bar as $x) { $foo[] = $x; } return $foo; }); Or what I have seen in real code: $response_text = "Do action"; store_response($response_text); // much later doSomeAction(function() { $response_text .= "Do other action"; // Note that accidental .= instead of = store_response($response_text); }); The code still works as expected, because things are NULL-initialized currently. Now with implicit auto-capture this is breaking. No ahead of time errors like parse or compile errors, which warn you. Just subtly breaking. Depending on where it's done, it may not be even noticed soon (variables with the same name at different places tend to have compatible types), just misbehave subtly. This is not acceptable. Now, when you suggest "function($bar) use (*) => $foo + $bar", I feel like half the point of the RFC, the conciseness of the syntax, is missed. And I'd also reject function($bar) => $foo + $bar as this would mean the "function" keyword introducing different semantics depending on what follows. [apart from being still not as concise as "fn"] Thanks, Bob

Michael Wallner

9 years ago
On 31/01/17 05:53, Stephen Reay wrote:
> Hi Andrea, All, > >> On 31 Jan 2017, at 08:12, Andrea Faulds <ajf@ajf.me> wrote: >> >> Is it necessary to introduce a new keyword, fn? >> >> I think you'd get a similar benefit from: >> >> function($x) => $arr[$x] >> >> Likewise, is it necessary to restrict auto-capture to the => >> syntax? Couldn't we allow the following? >> >> function ($x) { >> return $arr[$x]; >> } >> > > I agree that the `fn` keyword isn’t really necessary. I’ve never > quite understood how arrow functions with implied returns etc are > supposed to make for *more* readable code, but if they’re going to be > part of the language please at least keep some consistency with > regular closures.
Yes, I also think that keeping the function keyword would be better.
> > In the case that regular closures got auto-capture, would a > `use($foo, $bar, $baz)` segment on a closure still be honoured (i.e. > disable auto-capture), and would it have any impact (positive or > negative) on performance/memory usage? After several years of JS > closure ‘fun’ I kind of like that with PHP you only inherit the > variables you explicitly `use()` in closures.
Wouldn't there be just too many existing closures, which do not use `use` but (maybe) expect a clean scope?
-- Regards, Mike

Bob Weinand

9 years ago
Hey,
> Am 31.01.2017 um 11:23 schrieb Michael Wallner <mike@php.net>: > > On 31/01/17 05:53, Stephen Reay wrote: >> Hi Andrea, All, >> >>> On 31 Jan 2017, at 08:12, Andrea Faulds <ajf@ajf.me> wrote: >>> >>> Is it necessary to introduce a new keyword, fn? >>> >>> I think you'd get a similar benefit from: >>> >>> function($x) => $arr[$x] >>> >>> Likewise, is it necessary to restrict auto-capture to the => >>> syntax? Couldn't we allow the following? >>> >>> function ($x) { >>> return $arr[$x]; >>> } >>> >> >> I agree that the `fn` keyword isn’t really necessary. I’ve never >> quite understood how arrow functions with implied returns etc are >> supposed to make for *more* readable code, but if they’re going to be >> part of the language please at least keep some consistency with >> regular closures. > > Yes, I also think that keeping the function keyword would be better. > >> >> In the case that regular closures got auto-capture, would a >> `use($foo, $bar, $baz)` segment on a closure still be honoured (i.e. >> disable auto-capture), and would it have any impact (positive or >> negative) on performance/memory usage? After several years of JS >> closure ‘fun’ I kind of like that with PHP you only inherit the >> variables you explicitly `use()` in closures. > > Wouldn't there be just too many existing closures, which do not use > `use` but (maybe) expect a clean scope?
The RFC is exclusively proposing single-expression short Closures. We do NOT want multi-statement short Closures; it is a *feature* that generic Closures need an "use ($foo, $bar)". This vastly improves readability and debuggability - it basically tells you whether the variables inside the code are imported or not. As Stephen Reay notes:
>> After several years of JS >> closure ‘fun’ I kind of like that with PHP you only inherit the >> variables you explicitly `use()` in closures.
So, auto-import for generic Closures definitely isn't an option. Just on short, single-line Closures there is no benefit to "use ()", as EVERY variable used in the short Closure is supposed to be an imported variable. There is no point in forcing the user to distinguish between imported and local variable here. Also, using "fn" in favor of "function" has the advantage of less clutter in one line. Compare array_map(fn($x) => $x + 1) to array_map(function($x) => $x + 1) The syntactical construction is already pretty clearly showing what's going on. The "function" keyword itself is already larger than the whole body. It distracts while reading the actual code. Additionally, using "fn" is optically highlighting the fact that it's a short-Closure with auto-import and not a normal Closure with explicit import. Thanks, Bob

Niklas Keller

9 years ago
2017-01-31 12:14 GMT+01:00 Bob Weinand <bobwei9@hotmail.com>:
> Hey, > > > Am 31.01.2017 um 11:23 schrieb Michael Wallner <mike@php.net>: > > > > On 31/01/17 05:53, Stephen Reay wrote: > >> Hi Andrea, All, > >> > >>> On 31 Jan 2017, at 08:12, Andrea Faulds <ajf@ajf.me> wrote: > >>> > >>> Is it necessary to introduce a new keyword, fn? > >>> > >>> I think you'd get a similar benefit from: > >>> > >>> function($x) => $arr[$x] > >>> > >>> Likewise, is it necessary to restrict auto-capture to the => > >>> syntax? Couldn't we allow the following? > >>> > >>> function ($x) { > >>> return $arr[$x]; > >>> } > >>> > >> > >> I agree that the `fn` keyword isn’t really necessary. I’ve never > >> quite understood how arrow functions with implied returns etc are > >> supposed to make for *more* readable code, but if they’re going to be > >> part of the language please at least keep some consistency with > >> regular closures. > > > > Yes, I also think that keeping the function keyword would be better. > > > >> > >> In the case that regular closures got auto-capture, would a > >> `use($foo, $bar, $baz)` segment on a closure still be honoured (i.e. > >> disable auto-capture), and would it have any impact (positive or > >> negative) on performance/memory usage? After several years of JS > >> closure ‘fun’ I kind of like that with PHP you only inherit the > >> variables you explicitly `use()` in closures. > > > > Wouldn't there be just too many existing closures, which do not use > > `use` but (maybe) expect a clean scope? > > > The RFC is exclusively proposing single-expression short Closures. > We do NOT want multi-statement short Closures; it is a *feature* that > generic Closures need an "use ($foo, $bar)". > This vastly improves readability and debuggability - it basically tells > you whether the variables inside the code are imported or not. As Stephen > Reay notes: > >> After several years of JS > >> closure ‘fun’ I kind of like that with PHP you only inherit the > >> variables you explicitly `use()` in closures. > > > So, auto-import for generic Closures definitely isn't an option. > Just on short, single-line Closures there is no benefit to "use ()", as > EVERY variable used in the short Closure is supposed to be an imported > variable. There is no point in forcing the user to distinguish between > imported and local variable here. > > Also, using "fn" in favor of "function" has the advantage of less clutter > in one line. Compare > > array_map(fn($x) => $x + 1) > > to > > array_map(function($x) => $x + 1) >
"function" is actually easier to recognize than "fn" for me. Humans read things by the first and last letter + contained letters, they don't read each letter separately, so a little bit longer keyword doesn't hurt readability, it might be even improved, because "function" is a keyword people are used to. And it comes with the benefit of no BC break, because "function" is already a keyword. Also updating array_map(function ($x) => 2 * $x, [...]); to array_map(function ($x) use (...) { ... }, [...]); is a little bit easier then, just in case you need an additional statement there.
> The syntactical construction is already pretty clearly showing what's > going on. The "function" keyword itself is already larger than the whole > body.
Now we're counting chars again instead of keeping the focus on actual readability?
> It distracts while reading the actual code. >
I disagree here, as mentioned above.
> Additionally, using "fn" is optically highlighting the fact that it's a > short-Closure with auto-import and not a normal Closure with explicit > import. > > Thanks, > Bob
I think I prefer "function" instead of "fn", but I can also live with "fn". Regards, Niklas

Larry Garfield

9 years ago
On 01/31/2017 05:14 AM, Bob Weinand wrote:
>> >>> In the case that regular closures got auto-capture, would a >>> `use($foo, $bar, $baz)` segment on a closure still be honoured (i.e. >>> disable auto-capture), and would it have any impact (positive or >>> negative) on performance/memory usage? After several years of JS >>> closure ‘fun’ I kind of like that with PHP you only inherit the >>> variables you explicitly `use()` in closures. >> Wouldn't there be just too many existing closures, which do not use >> `use` but (maybe) expect a clean scope? > > The RFC is exclusively proposing single-expression short Closures. > We do NOT want multi-statement short Closures; it is a *feature* that generic Closures need an "use ($foo, $bar)". > This vastly improves readability and debuggability - it basically tells you whether the variables inside the code are imported or not. As Stephen Reay notes: >>> After several years of JS >>> closure ‘fun’ I kind of like that with PHP you only inherit the >>> variables you explicitly `use()` in closures. > > So, auto-import for generic Closures definitely isn't an option. > Just on short, single-line Closures there is no benefit to "use ()", as EVERY variable used in the short Closure is supposed to be an imported variable. There is no point in forcing the user to distinguish between imported and local variable here. > > Also, using "fn" in favor of "function" has the advantage of less clutter in one line. Compare > > array_map(fn($x) => $x + 1) > > to > > array_map(function($x) => $x + 1) > > The syntactical construction is already pretty clearly showing what's going on. The "function" keyword itself is already larger than the whole body. It distracts while reading the actual code. > Additionally, using "fn" is optically highlighting the fact that it's a short-Closure with auto-import and not a normal Closure with explicit import. > > Thanks, > Bob
I must agree with Bob and the other authors. The entire point of this RFC is to reduce the amount of typing, and therefore reading, that goes into using simple closures as first-class values. Using longer keywords instead of shorter ones is counter to that aim. It sounds like the earlier proposal of keyword-less closures isn't technically feasible or it would make sense to argue for that. My question is why there's no mention of HHVM short closures, or the previous RFC to take that approach. See: https://docs.hhvm.com/hack/lambdas/introduction If there's a good reason to not use that syntax, OK, but that should be stated explicitly in the RFC with links to both HHVM and to the previous short-closure RFC. I also echo the previous call to clarify with examples how types would be used, syntactically. Since there is no "return" keyword used, that implies that no "yield" keyword can be used, either. That is, arrow-function generators are not supported. Is that correct? (In context they may not make sense to have, but that should be clarified explicitly in the RFC.) Overall I am +1 on this RFC. --Larry Garfield

Michael Morris

9 years ago
On Tue, Jan 31, 2017 at 12:29 PM, Larry Garfield <larry@garfieldtech.com> wrote:
> On 01/31/2017 05:14 AM, Bob Weinand wrote: > >> >>> In the case that regular closures got auto-capture, would a >>>> `use($foo, $bar, $baz)` segment on a closure still be honoured (i.e. >>>> disable auto-capture), and would it have any impact (positive or >>>> negative) on performance/memory usage? After several years of JS >>>> closure ‘fun’ I kind of like that with PHP you only inherit the >>>> variables you explicitly `use()` in closures. >>>> >>> Wouldn't there be just too many existing closures, which do not use >>> `use` but (maybe) expect a clean scope? >>> >> >> The RFC is exclusively proposing single-expression short Closures. >> We do NOT want multi-statement short Closures; it is a *feature* that >> generic Closures need an "use ($foo, $bar)". >> This vastly improves readability and debuggability - it basically tells >> you whether the variables inside the code are imported or not. As Stephen >> Reay notes: >> >>> After several years of JS >>>> closure ‘fun’ I kind of like that with PHP you only inherit the >>>> variables you explicitly `use()` in closures. >>>> >>> >> So, auto-import for generic Closures definitely isn't an option. >> Just on short, single-line Closures there is no benefit to "use ()", as >> EVERY variable used in the short Closure is supposed to be an imported >> variable. There is no point in forcing the user to distinguish between >> imported and local variable here. >> >> Also, using "fn" in favor of "function" has the advantage of less clutter >> in one line. Compare >> >> array_map(fn($x) => $x + 1) >> >> to >> >> array_map(function($x) => $x + 1) >> >> The syntactical construction is already pretty clearly showing what's >> going on. The "function" keyword itself is already larger than the whole >> body. It distracts while reading the actual code. >> Additionally, using "fn" is optically highlighting the fact that it's a >> short-Closure with auto-import and not a normal Closure with explicit >> import. >> >> Thanks, >> Bob >> > > I must agree with Bob and the other authors. The entire point of this RFC > is to reduce the amount of typing, and therefore reading, that goes into > using simple closures as first-class values. Using longer keywords instead > of shorter ones is counter to that aim. It sounds like the earlier > proposal of keyword-less closures isn't technically feasible or it would > make sense to argue for that. > > My question is why there's no mention of HHVM short closures, or the > previous RFC to take that approach. See: > > https://docs.hhvm.com/hack/lambdas/introduction > > >
For what it's worth I'd rather look at array_map( $x ==> $x + 1); than array_map( fn($x) => $x + 1 ) Not to mention the former isn't a bc break.

David Rodrigues

9 years ago
I guess that should avoid the usage of fn() or function() before arguments (or then make it optional, but I don't like to give much options). Some possibilites: array_map(($x) return $x + 1); // or array_map(($x) = $x + 1); // or array_map(($x) => $x + 1); // or array_map(($x) { $x + 1 }); Then: array_map(($x) use ($y) { $x + $y }); array_map(($x) { $x + $y }); ​// maybe use($y) is needless here array_map(($x) { $x + $this->y }); Or if arguments could be omitted: array_map({ $0 + 1 }); 2017-01-31 16:16 GMT-02:00 Michael Morris <tendoaki@gmail.com>:
> On Tue, Jan 31, 2017 at 12:29 PM, Larry Garfield <larry@garfieldtech.com> > wrote: > > > On 01/31/2017 05:14 AM, Bob Weinand wrote: > > > >> > >>> In the case that regular closures got auto-capture, would a > >>>> `use($foo, $bar, $baz)` segment on a closure still be honoured (i.e. > >>>> disable auto-capture), and would it have any impact (positive or > >>>> negative) on performance/memory usage? After several years of JS > >>>> closure ‘fun’ I kind of like that with PHP you only inherit the > >>>> variables you explicitly `use()` in closures. > >>>> > >>> Wouldn't there be just too many existing closures, which do not use > >>> `use` but (maybe) expect a clean scope? > >>> > >> > >> The RFC is exclusively proposing single-expression short Closures. > >> We do NOT want multi-statement short Closures; it is a *feature* that > >> generic Closures need an "use ($foo, $bar)". > >> This vastly improves readability and debuggability - it basically tells > >> you whether the variables inside the code are imported or not. As > Stephen > >> Reay notes: > >> > >>> After several years of JS > >>>> closure ‘fun’ I kind of like that with PHP you only inherit the > >>>> variables you explicitly `use()` in closures. > >>>> > >>> > >> So, auto-import for generic Closures definitely isn't an option. > >> Just on short, single-line Closures there is no benefit to "use ()", as > >> EVERY variable used in the short Closure is supposed to be an imported > >> variable. There is no point in forcing the user to distinguish between > >> imported and local variable here. > >> > >> Also, using "fn" in favor of "function" has the advantage of less > clutter > >> in one line. Compare > >> > >> array_map(fn($x) => $x + 1) > >> > >> to > >> > >> array_map(function($x) => $x + 1) > >> > >> The syntactical construction is already pretty clearly showing what's > >> going on. The "function" keyword itself is already larger than the whole > >> body. It distracts while reading the actual code. > >> Additionally, using "fn" is optically highlighting the fact that it's a > >> short-Closure with auto-import and not a normal Closure with explicit > >> import. > >> > >> Thanks, > >> Bob > >> > > > > I must agree with Bob and the other authors. The entire point of this > RFC > > is to reduce the amount of typing, and therefore reading, that goes into > > using simple closures as first-class values. Using longer keywords > instead > > of shorter ones is counter to that aim. It sounds like the earlier > > proposal of keyword-less closures isn't technically feasible or it would > > make sense to argue for that. > > > > My question is why there's no mention of HHVM short closures, or the > > previous RFC to take that approach. See: > > > > https://docs.hhvm.com/hack/lambdas/introduction > > > > > > > > For what it's worth I'd rather look at > > array_map( $x ==> $x + 1); > > than > > array_map( fn($x) => $x + 1 ) > > Not to mention the former isn't a bc break. >
-- David Rodrigues

Christoph Becker

9 years ago
On 31.01.2017 at 19:16, Michael Morris wrote:
> On Tue, Jan 31, 2017 at 12:29 PM, Larry Garfield <larry@garfieldtech.com> > wrote: > >> My question is why there's no mention of HHVM short closures, or the >> previous RFC to take that approach. See: >> >> https://docs.hhvm.com/hack/lambdas/introduction > > For what it's worth I'd rather look at > > array_map( $x ==> $x + 1); > > than > > array_map( fn($x) => $x + 1 ) > > Not to mention the former isn't a bc break.
Neither is supposed to work, though. :) Anyhow, I'm not sure whether I'd prefer array_map($a, $b, $c ==> $a + $b + $c, $a1, $a2, $a3) over array_map(fn($a, $b, $c) => $a + $b + $c, $a1, $a2, $a3) or maybe array_map(fn $a, $b, $c => $a + $b + $c, $a1, $a2, $a3) Somehow, I tend to like a trailing keyword for better left-to-right readability.
-- Christoph M. Becker

Bob Weinand

9 years ago
> Am 31.01.2017 um 19:41 schrieb Christoph M. Becker <cmbecker69@gmx.de>: > > On 31.01.2017 at 19:16, Michael Morris wrote: > >> On Tue, Jan 31, 2017 at 12:29 PM, Larry Garfield <larry@garfieldtech.com> >> wrote: >> >>> My question is why there's no mention of HHVM short closures, or the >>> previous RFC to take that approach. See: >>> >>> https://docs.hhvm.com/hack/lambdas/introduction >> >> For what it's worth I'd rather look at >> >> array_map( $x ==> $x + 1); >> >> than >> >> array_map( fn($x) => $x + 1 ) >> >> Not to mention the former isn't a bc break. > > Neither is supposed to work, though. :) > > Anyhow, I'm not sure whether I'd prefer > > array_map($a, $b, $c ==> $a + $b + $c, $a1, $a2, $a3) > > over > > array_map(fn($a, $b, $c) => $a + $b + $c, $a1, $a2, $a3) > > or maybe > > array_map(fn $a, $b, $c => $a + $b + $c, $a1, $a2, $a3) > > Somehow, I tend to like a trailing keyword for better left-to-right > readability. > > -- > Christoph M. Becker
The RFC states that we're needing some form of a prefix in order to avoid implementing gigantic lexer hacks. HHVM internally implements it by parsing some part of the syntax INSIDE the lexer and then emitting a token before the first parameter to tell the parser where a short Closure begins. Having a normal terminal symbol easily allows the parser to detect short Closures, without any hacks. It is just not a practical option from a technical point of view, and thus not worth even considering. Bob

Marco Pivetta

9 years ago
Just throwing it in here while commuting, so it's a top-post with no references. Saw it yesterday on reddit (!!! Reddit being useful for once !!!): $callback = |$x| => $x ** 2; On 31 Jan 2017 22:44, "Bob Weinand" <bobwei9@hotmail.com> wrote:

Nikita

9 years ago
On Mon, 30 Jan 2017 20:55:07 +0300, Levi Morrison <levim@php.net> wrote:
> Bob Weinand and I are happy to announce that the [Arrow Functions][1] > RFC is moving into the public discussion phase. We have been > collaborating on this RFC for many months now and finally have a > proposal we are happy to discuss in the open. > > Here is an example of an existing closure: > > function ($x) use ($arr) { > return $arr[$x]; > } > > This RFC proposes syntax and semantics to simplify this common usage to: > > fn($x) => $arr[$x] > > More details are in the RFC. The [implementation][2] currently has no > known issues and is ready for you to download, build and test, which > we encourage you to do. > > We look forward to a productive discussion period and are happy to > answer questions. > > For historical purposes, the revision of this RFC is currently at > [1485798604][3]. > > [1]: https://wiki.php.net/rfc/arrow_functions > [2]: https://github.com/morrisonlevi/php-src/tree/arrow_functions > [3]: https://wiki.php.net/rfc/arrow_functions?rev=1485798604
Hey Levi, Bob, that looks very good. The fn prefix is peculiar yes but it's alright, it doesn't harm neither readability nor writability, it even has some precedences in other languages (think Rust, Elixir) and as we all know it is necessary for parser. Thanks for the work, I hope it lands in PHP.

Yasuo Ohgaki

9 years ago
Hi Levi, On Tue, Jan 31, 2017 at 2:55 AM, Levi Morrison <levim@php.net> wrote:
> This RFC proposes syntax and semantics to simplify this common usage to: > > fn($x) => $arr[$x] >
Could you explain why fn() cannot be removed like ES2015. Rowan's syntax sounds attractive to me if fn() cannot be removed. fn($x => $x * 2) Or since many of us like "function", it could be function($x => $x * 2) I don't have strong preference, but some may have. I suggest separate vote into 2 votes. - Introduce arrow function - Prefered syntax Regards,
-- Yasuo Ohgaki yohgaki@ohgaki.net

Nicolas Grekas

9 years ago
Or just drop any "fn" or "function" keyword, eg ($x, $y) => foo($x, $y); array_map(($x) => $x + 1); ?

Yasuo Ohgaki

9 years ago
On Tue, Jan 31, 2017 at 9:06 PM, Nicolas Grekas < nicolas.grekas+php@gmail.com> wrote:
> Or just drop any "fn" or "function" keyword, eg > > ($x, $y) => foo($x, $y); > > array_map(($x) => $x + 1); > > ? >
I like your syntax if it cannot be like ES2015 syntax.
-- Yasuo Ohgaki yohgaki@ohgaki.net

Alain Williams

9 years ago
On Tue, Jan 31, 2017 at 01:06:25PM +0100, Nicolas Grekas wrote:
> Or just drop any "fn" or "function" keyword, eg > > ($x, $y) => foo($x, $y); > > array_map(($x) => $x + 1);
That has the great advantage of being much as Javascript does this. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions
-- Alain Williams Linux/GNU Consultant - Mail systems, Web sites, Networking, Programmer, IT Lecturer. +44 (0) 787 668 0256 http://www.phcomp.co.uk/ Parliament Hill Computers Ltd. Registration Information: http://www.phcomp.co.uk/contact.php #include <std_disclaimer.h>

Michał Brzuchalski

9 years ago
2017-01-31 13:20 GMT+01:00 Alain Williams <addw@phcomp.co.uk>:
> On Tue, Jan 31, 2017 at 01:06:25PM +0100, Nicolas Grekas wrote: > > Or just drop any "fn" or "function" keyword, eg > > > > ($x, $y) => foo($x, $y); > > > > array_map(($x) => $x + 1); > > That has the great advantage of being much as Javascript does this. > > https://developer.mozilla.org/en/docs/Web/JavaScript/ > Reference/Functions/Arrow_functions > >
IMO it'll be hard to detect arrow function then. Consider an example: $y = 'a'; $x = 1; $a = [ $y => 'b', ($x) => $x + 1, ];
> -- > Alain Williams > Linux/GNU Consultant - Mail systems, Web sites, Networking, Programmer, IT > Lecturer. > +44 (0) 787 668 0256 http://www.phcomp.co.uk/ > Parliament Hill Computers Ltd. Registration Information: > http://www.phcomp.co.uk/contact.php > #include <std_disclaimer.h> > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >
-- regards / pozdrawiam, -- Michał Brzuchalski about.me/brzuchal brzuchalski.com

Niklas Keller

9 years ago
Alain Williams <addw@phcomp.co.uk> schrieb am Di., 31. Jan. 2017, 13:20:
> On Tue, Jan 31, 2017 at 01:06:25PM +0100, Nicolas Grekas wrote: > > Or just drop any "fn" or "function" keyword, eg > > > > ($x, $y) => foo($x, $y); > > > > array_map(($x) => $x + 1); > > That has the great advantage of being much as Javascript does this. > > > https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions
As noted in the RFC, this isn't possible due to ambiguities with array keys and yield expressions with keys. Regards, Niklas

Nicolas Grekas

9 years ago
> > As noted in the RFC, this isn't possible due to ambiguities with array > keys and yield expressions with keys. >
There are not ambiguities technically, so it is possible if we want to: $a = [ $y => 'b', ($x) => $x + 1, // key, value pair ]; $a = [ $y => 'b', (($x) => $x + 1), // closure ];

Niklas Keller

9 years ago
Nicolas Grekas <nicolas.grekas+php@gmail.com> schrieb am Di., 31. Jan. 2017, 13:45:
> > > > As noted in the RFC, this isn't possible due to ambiguities with array > > keys and yield expressions with keys. > > > > There are not ambiguities technically, so it is possible if we want to: > > $a = [ > $y => 'b', > ($x) => $x + 1, // key, value pair > ]; > > $a = [ > $y => 'b', > (($x) => $x + 1), // closure > ]; >
Well, it is ambiguous. Your solution just arbitrarily resolves it to one of them. But as far as I know there are more problems like supporting types that make it quite complicated with that syntax. Regards, Niklas

Yasuo Ohgaki

9 years ago
Hi Levi, On Tue, Jan 31, 2017 at 8:38 PM, Yasuo Ohgaki <yohgaki@ohgaki.net> wrote:
> On Tue, Jan 31, 2017 at 2:55 AM, Levi Morrison <levim@php.net> wrote: > >> This RFC proposes syntax and semantics to simplify this common usage to: >> >> fn($x) => $arr[$x] >> > > Could you explain why fn() cannot be removed like ES2015.
I guess current PHP parser has to determine token type as they processed. So distinguished keyword is needed. I don't have problem with the proposed syntax. Large change is not preferred and current way should be faster. Regards,
-- Yasuo Ohgaki yohgaki@ohgaki.net

Levi Morrison

9 years ago
On Mon, Jan 30, 2017 at 10:55 AM, Levi Morrison <levim@php.net> wrote:
> Bob Weinand and I are happy to announce that the [Arrow Functions][1] > RFC is moving into the public discussion phase. We have been > collaborating on this RFC for many months now and finally have a > proposal we are happy to discuss in the open. > > Here is an example of an existing closure: > > function ($x) use ($arr) { > return $arr[$x]; > } > > This RFC proposes syntax and semantics to simplify this common usage to: > > fn($x) => $arr[$x] > > More details are in the RFC. The [implementation][2] currently has no > known issues and is ready for you to download, build and test, which > we encourage you to do. > > We look forward to a productive discussion period and are happy to > answer questions. > > For historical purposes, the revision of this RFC is currently at > [1485798604][3]. > > [1]: https://wiki.php.net/rfc/arrow_functions > [2]: https://github.com/morrisonlevi/php-src/tree/arrow_functions > [3]: https://wiki.php.net/rfc/arrow_functions?rev=1485798604
Thank you to everyone who has participated in the discussion so far. Several people have asked for examples of type declarations. I have updated the RFC accordingly and also added an example for by-ref parameters and returns. Here are the examples: fn (array $x) => $x fn (): int => 42 fn &(array &$xs) => $xs I have also made some minor improvements to the formatting in various places.

Levi Morrison

9 years ago
On Mon, Jan 30, 2017 at 10:55 AM, Levi Morrison <levim@php.net> wrote:

Levi Morrison

9 years ago
On Mon, Jan 30, 2017 at 10:55 AM, Levi Morrison <levim@php.net> wrote:
> Bob Weinand and I are happy to announce that the [Arrow Functions][1] > RFC is moving into the public discussion phase. We have been > collaborating on this RFC for many months now and finally have a > proposal we are happy to discuss in the open. > > Here is an example of an existing closure: > > function ($x) use ($arr) { > return $arr[$x]; > } > > This RFC proposes syntax and semantics to simplify this common usage to: > > fn($x) => $arr[$x] > > More details are in the RFC. The [implementation][2] currently has no > known issues and is ready for you to download, build and test, which > we encourage you to do. > > We look forward to a productive discussion period and are happy to > answer questions. > > For historical purposes, the revision of this RFC is currently at > [1485798604][3]. > > [1]: https://wiki.php.net/rfc/arrow_functions > [2]: https://github.com/morrisonlevi/php-src/tree/arrow_functions > [3]: https://wiki.php.net/rfc/arrow_functions?rev=1485798604
Thanks to everyone who has participated in the discussion thus far. Primarily the feedback has been directed at the `fn` keyword. Let me provide two benefits and drawbacks of using `fn` as a keyword: 1. `fn` is searchable in search engines and in our manual 2. Is more intuitive than just syntax However, `fn` does have downsides: 1. Can break existing code 2. We already have a similar keyword `function` To that end, I'd like to gauge interest in a pure syntax based alternative that is similar to Rust and Ruby. Instead of: fn(params) => expr What about: |params| => expr This trades the advantages of the keyword for the advantages of pure syntax, and happens to be two characters shorter. To be explicit: 1. Preserves 100% backwards compatibility 2. Avoids having two keywords that both mean "function" 3. Is not easily searchable in engines or in the manual 4. Is a tad bit shorter What do you think, Internals?

Levi Morrison

9 years ago
On Fri, Feb 3, 2017 at 10:48 AM, Levi Morrison <levim@php.net> wrote:
> On Mon, Jan 30, 2017 at 10:55 AM, Levi Morrison <levim@php.net> wrote: >> Bob Weinand and I are happy to announce that the [Arrow Functions][1] >> RFC is moving into the public discussion phase. We have been >> collaborating on this RFC for many months now and finally have a >> proposal we are happy to discuss in the open. >> >> Here is an example of an existing closure: >> >> function ($x) use ($arr) { >> return $arr[$x]; >> } >> >> This RFC proposes syntax and semantics to simplify this common usage to: >> >> fn($x) => $arr[$x] >> >> More details are in the RFC. The [implementation][2] currently has no >> known issues and is ready for you to download, build and test, which >> we encourage you to do. >> >> We look forward to a productive discussion period and are happy to >> answer questions. >> >> For historical purposes, the revision of this RFC is currently at >> [1485798604][3]. >> >> [1]: https://wiki.php.net/rfc/arrow_functions >> [2]: https://github.com/morrisonlevi/php-src/tree/arrow_functions >> [3]: https://wiki.php.net/rfc/arrow_functions?rev=1485798604 > > Thanks to everyone who has participated in the discussion thus far. > Primarily the feedback has been directed at the `fn` keyword. Let me > provide two benefits and drawbacks of using `fn` as a keyword: > > 1. `fn` is searchable in search engines and in our manual > 2. Is more intuitive than just syntax > > However, `fn` does have downsides: > > 1. Can break existing code > 2. We already have a similar keyword `function` > > To that end, I'd like to gauge interest in a pure syntax based > alternative that is similar to Rust and Ruby. > Instead of: > > fn(params) => expr > > What about: > > |params| => expr > > This trades the advantages of the keyword for the advantages of pure > syntax, and happens to be two characters shorter. To be explicit: > > 1. Preserves 100% backwards compatibility > 2. Avoids having two keywords that both mean "function" > 3. Is not easily searchable in engines or in the manual > 4. Is a tad bit shorter > > What do you think, Internals?
One more thing: I'd like to re-emphasize that the syntax that JavaScript uses and the one that HHVM/Hack uses are ambiguous in the current class of our grammar. The following will not work unless we move to a more powerful grammar and parser class: (params) => expr (params) ==> expr This is why an un-ambiguous prefix is necessary: the prefix breaks the ambiguities. The syntax I have suggested in the RFC and the one I suggested just now are not ambiguous because distinct prefixes: fn(params) => expr |params| => expr I look forward to more discussion!

Michael Morris

9 years ago
On Fri, Feb 3, 2017 at 12:53 PM, Levi Morrison <levim@php.net> wrote:
> > > To that end, I'd like to gauge interest in a pure syntax based > > alternative that is similar to Rust and Ruby. > > Instead of: > > > > fn(params) => expr > > > > What about: > > > > |params| => expr >
Looks great to me from up here in the peanut gallery.

David Rodrigues

9 years ago
Hello folks! I just not understand why "function" should be abbreviated. It's about "how less character better"? I don't see it too much on PHP. I guess that is more simple keep what exists current "function", that all knows about (that should be better than the next example): $mapped = array_map(function($x) => $x + $y); // vs current: $mapped = array_map(function($x) use($y) { return $x + $y }); Or even, I too don't know why just ($x) => is an issue. There some possible conflict why that? 2017-02-03 16:21 GMT-02:00 Michael Morris <tendoaki@gmail.com>:
> On Fri, Feb 3, 2017 at 12:53 PM, Levi Morrison <levim@php.net> wrote: > > > > > To that end, I'd like to gauge interest in a pure syntax based > > > alternative that is similar to Rust and Ruby. > > > Instead of: > > > > > > fn(params) => expr > > > > > > What about: > > > > > > |params| => expr > > > > Looks great to me from up here in the peanut gallery. >
-- David Rodrigues

Levi Morrison

9 years ago
On Fri, Feb 3, 2017 at 11:46 AM, David Rodrigues <david.proweb@gmail.com> wrote:
> Or even, I too don't know why just ($x) => is an issue. There some possible > conflict why that?
Yes, this conflicts with existing syntax. The following code snippets are valid today: [($x) => $x + $y] yield ($x) => $x + $y There are other issues as well; this is just the easiest to point out.

Andrew Faulds

9 years ago
Hi David, David Rodrigues wrote:
> Hello folks! > I just not understand why "function" should be abbreviated. It's about "how > less character better"? I don't see it too much on PHP. I guess that is > more simple keep what exists current "function", that all knows about (that > should be better than the next example): > > $mapped = array_map(function($x) => $x + $y); // vs current: > $mapped = array_map(function($x) use($y) { return $x + $y });
I feel the same way. It would be nice to have shorter syntax, but it sacrifices readability and familiarity here, and adds yet another new keyword. It also feels inconsistent… isn't "fn" just short for "function"? Why is it exclusive to the => syntax? Thanks.
-- Andrea Faulds https://ajf.me/

Levi Morrison

9 years ago
On Fri, Feb 3, 2017 at 12:18 PM, Andrea Faulds <ajf@ajf.me> wrote:
> Hi David, > > David Rodrigues wrote: >> >> Hello folks! >> I just not understand why "function" should be abbreviated. It's about >> "how >> less character better"? I don't see it too much on PHP. I guess that is >> more simple keep what exists current "function", that all knows about >> (that >> should be better than the next example): >> >> $mapped = array_map(function($x) => $x + $y); // vs current: >> $mapped = array_map(function($x) use($y) { return $x + $y }); > > > I feel the same way. It would be nice to have shorter syntax, but it > sacrifices readability and familiarity here, and adds yet another new > keyword. > > It also feels inconsistent… isn't "fn" just short for "function"? Why is it > exclusive to the => syntax?
This is not exactly on topic... unless you are implying you'd prefer the `|$x| => $x + $y`? Maybe you missed [this][1] message? [1]: http://news.php.net/php.internals/98136

Ilija Tovilo

9 years ago
I like the suggested syntax. The only drawback I see is that it inhibits the future addition of union types for closures:     |int | float $x| => $x Adding parentheses of course resolves the issue but looks a bit awkward:     |(int | float) $x| => $x Apart from that I have nothing to complain about. I'd be happy either way. On 3 Feb 2017, 21:24 +0100, Levi Morrison <levim@php.net>, wrote:

Michael Morris

9 years ago
On Fri, Feb 3, 2017 at 3:34 PM, <ilija.tovilo@me.com> wrote:
> I like the suggested syntax. The only drawback I see is that it inhibits > the future addition of union types for closures: > > |int | float $x| => $x > > Adding parentheses of course resolves the issue but looks a bit awkward: > > |(int | float) $x| => $x > > Apart from that I have nothing to complain about. I'd be happy either way. >
Good point, but union types are going to come up in this context I think. Remember, these are for one line functions, which highly limits what they can do.

Aaron Piotrowski

9 years ago
> On Feb 3, 2017, at 2:34 PM, ilija.tovilo@me.com wrote: > > I like the suggested syntax. The only drawback I see is that it inhibits the future addition of union types for closures: > > |int | float $x| => $x > > Adding parentheses of course resolves the issue but looks a bit awkward: > > |(int | float) $x| => $x > > Apart from that I have nothing to complain about. I'd be happy either way. >
While it may be ugly, I do not believe that this has any ambiguity. $callback = |int|float $x| => $x ** 2; When the second | is not followed by =>, the parser should be able to discern that a union type is being used. Regards, Aaron Piotrowski

Stephen Reay

9 years ago
> On 4 Feb 2017, at 07:25, Aaron Piotrowski <aaron@trowski.com> wrote: > > $callback = |int|float $x| => $x ** 2;
Forget the parser, you're giving my eyes diabetes trying to read that. As has been said before, PHP is relatively verbose compared to other languages. That makes it slightly more characters to type, but it also makes it absolutely clear what is happening. As Niklas said, all ambiguity/clarity issues are solved by using "function", at the cost of 6 characters. Suggesting that a search for arrow functions will be easier with <insert random character here> and then using grep (which could also easily match arrow functions using "function") as your example search seems odd to me.

Niklas Keller

9 years ago
2017-02-03 21:23 GMT+01:00 Levi Morrison <levim@php.net>:
> On Fri, Feb 3, 2017 at 12:18 PM, Andrea Faulds <ajf@ajf.me> wrote: > > Hi David, > > > > David Rodrigues wrote: > >> > >> Hello folks! > >> I just not understand why "function" should be abbreviated. It's about > >> "how > >> less character better"? I don't see it too much on PHP. I guess that is > >> more simple keep what exists current "function", that all knows about > >> (that > >> should be better than the next example): > >> > >> $mapped = array_map(function($x) => $x + $y); // vs current: > >> $mapped = array_map(function($x) use($y) { return $x + $y }); > > > > > > I feel the same way. It would be nice to have shorter syntax, but it > > sacrifices readability and familiarity here, and adds yet another new > > keyword. > > > > It also feels inconsistent… isn't "fn" just short for "function"? Why is > it > > exclusive to the => syntax? > > This is not exactly on topic... unless you are implying you'd prefer > the `|$x| => $x + $y`? Maybe you missed [this][1] message? >
Why is using "function" instead of "fn" not on topic? Thanks to everyone who has participated in the discussion thus far.
> Primarily the feedback has been directed at the `fn` keyword. Let me > provide two benefits and drawbacks of using `fn` as a keyword: > 1. `fn` is searchable in search engines and in our manual >
Just as "php function" is, too: http://php.net/manual/en/language.functions.php
> 2. Is more intuitive than just syntax >
As is "function", too. With the added benefit that people are already familiar with it.
> However, `fn` does have downsides: > 1. Can break existing code >
Which doesn't happen with reusing "function".
> 2. We already have a similar keyword `function` >
Right, so why not use that?
> To that end, I'd like to gauge interest in a pure syntax based > alternative that is similar to Rust and Ruby. > Instead of: > fn(params) => expr > What about: > |params| => expr > This trades the advantages of the keyword for the advantages of pure > syntax, and happens to be two characters shorter. To be explicit: > 1. Preserves 100% backwards compatibility > 2. Avoids having two keywords that both mean "function" > 3. Is not easily searchable in engines or in the manual > 4. Is a tad bit shorter >
1, 2, and 3 are also solved by using "function". 4 is counting characters instead of focusing on readability. There are more drawbacks to that syntax like no parameters looking pretty weird: || => Regards, Niklas

Levi Morrison

9 years ago
On Fri, Feb 3, 2017 at 1:37 PM, Niklas Keller <me@kelunik.com> wrote:
> 2017-02-03 21:23 GMT+01:00 Levi Morrison <levim@php.net>: >> >> On Fri, Feb 3, 2017 at 12:18 PM, Andrea Faulds <ajf@ajf.me> wrote: >> > Hi David, >> > >> > David Rodrigues wrote: >> >> >> >> Hello folks! >> >> I just not understand why "function" should be abbreviated. It's about >> >> "how >> >> less character better"? I don't see it too much on PHP. I guess that is >> >> more simple keep what exists current "function", that all knows about >> >> (that >> >> should be better than the next example): >> >> >> >> $mapped = array_map(function($x) => $x + $y); // vs current: >> >> $mapped = array_map(function($x) use($y) { return $x + $y }); >> > >> > >> > I feel the same way. It would be nice to have shorter syntax, but it >> > sacrifices readability and familiarity here, and adds yet another new >> > keyword. >> > >> > It also feels inconsistent… isn't "fn" just short for "function"? Why is >> > it >> > exclusive to the => syntax? >> >> This is not exactly on topic... unless you are implying you'd prefer >> the `|$x| => $x + $y`? Maybe you missed [this][1] message? > > > Why is using "function" instead of "fn" not on topic?
I did not ask for general syntax suggestions. What I am asking about is specifically what the preference people might have between these two options: fn(params) => expr |params| => expr As well as potential issues (thanks, Ilija, for pointing out a theoretical issue with union types). ---- As a disclaimer I'm trying to guide the discussion to these two options, not suppress suggestions I don't like.

Björn Larsson

9 years ago
Den 2017-02-03 kl. 21:46, skrev Levi Morrison:
> On Fri, Feb 3, 2017 at 1:37 PM, Niklas Keller <me@kelunik.com> wrote: >> 2017-02-03 21:23 GMT+01:00 Levi Morrison <levim@php.net>: >>> On Fri, Feb 3, 2017 at 12:18 PM, Andrea Faulds <ajf@ajf.me> wrote: >>>> Hi David, >>>> >>>> David Rodrigues wrote: >>>>> Hello folks! >>>>> I just not understand why "function" should be abbreviated. It's about >>>>> "how >>>>> less character better"? I don't see it too much on PHP. I guess that is >>>>> more simple keep what exists current "function", that all knows about >>>>> (that >>>>> should be better than the next example): >>>>> >>>>> $mapped = array_map(function($x) => $x + $y); // vs current: >>>>> $mapped = array_map(function($x) use($y) { return $x + $y }); >>>> >>>> I feel the same way. It would be nice to have shorter syntax, but it >>>> sacrifices readability and familiarity here, and adds yet another new >>>> keyword. >>>> >>>> It also feels inconsistent… isn't "fn" just short for "function"? Why is >>>> it >>>> exclusive to the => syntax? >>> This is not exactly on topic... unless you are implying you'd prefer >>> the `|$x| => $x + $y`? Maybe you missed [this][1] message? >> >> Why is using "function" instead of "fn" not on topic? > I did not ask for general syntax suggestions. What I am asking about > is specifically what the preference people might have between these > two options: > > fn(params) => expr > |params| => expr > > As well as potential issues (thanks, Ilija, for pointing out a > theoretical issue with union types). > > ---- > > As a disclaimer I'm trying to guide the discussion to these two > options, not suppress suggestions I don't like. >
I can live with both, maybe with a preference for the last one. Using function with another semantic I don't like at all. Imagine for example if different kind of loops had the same starting keyword (for for everything ;-). Also using fn or || helps when searching in a codebase for all ordinary functions and no arrow ones, e.g. grep 'function(\$' files would give everything with fucntion keyword. Anothe angle I came to think of is if PHP in the future would have async / await functionality. How does that play together with arrow functions? HHVM has some example: https://docs.hhvm.com/hack/async/blocks Anyway, I do appreciate that finally arrow functions in PHP are on the horizon :-) Regards //Björn Larsson

Michael Morris

9 years ago
On Fri, Feb 3, 2017 at 3:37 PM, Niklas Keller <me@kelunik.com> wrote:
> > > There are more drawbacks to that syntax like no parameters looking pretty > weird: || => > >
I can't think of a valid example of an arrow function without any arguments at all. These functions are very simple iterators to plug into things like array_map. If you can think of one please post it.

Fleshgrinder

9 years ago
On 2/3/2017 11:26 PM, Michael Morris wrote:
> On Fri, Feb 3, 2017 at 3:37 PM, Niklas Keller <me@kelunik.com> wrote: >> >> >> There are more drawbacks to that syntax like no parameters looking pretty >> weird: || => >> >> > I can't think of a valid example of an arrow function without any arguments > at all. These functions are very simple iterators to plug into things like > array_map. If you can think of one please post it. >
There are many situations where one might want a closure that takes no arguments. ``` $option->unwrapOrThrow(|| => new Exception('my message')); ``` Creating a supplier callable is often less resource intensive than actually computing the supplied value. Rust has exactly that syntax but it can become rather cryptic and PHP is a verbose language in general. I think that it is best for PHP to go for `function` to keep things nicely aligned and to avoid problems with union types (which we really need).
-- Richard "Fleshgrinder" Fussenegger

Niklas Keller

9 years ago
2017-02-03 23:26 GMT+01:00 Michael Morris <tendoaki@gmail.com>:
> On Fri, Feb 3, 2017 at 3:37 PM, Niklas Keller <me@kelunik.com> wrote: > > > > > > There are more drawbacks to that syntax like no parameters looking pretty > > weird: || => > > > > > I can't think of a valid example of an arrow function without any arguments > at all. These functions are very simple iterators to plug into things like > array_map. If you can think of one please post it. >
One example might be callbacks operating on `$this`: register_some_callback(|| => $this->someFlag = false); Another example are supplier functions as mentioned by Fleshgrinder. Regards, Niklas

Tony Marston

9 years ago
"Andrea Faulds" wrote in message news:19.45.38491.677D4985@pb1.pair.com...
> >Hi David, > >David Rodrigues wrote: >> Hello folks! >> I just not understand why "function" should be abbreviated. It's about >> "how >> less character better"? I don't see it too much on PHP. I guess that is >> more simple keep what exists current "function", that all knows about >> (that >> should be better than the next example): >> >> $mapped = array_map(function($x) => $x + $y); // vs current: >> $mapped = array_map(function($x) use($y) { return $x + $y }); > >I feel the same way. It would be nice to have shorter syntax, but it >sacrifices readability and familiarity here, and adds yet another new >keyword. > >It also feels inconsistent… isn't "fn" just short for "function"? Why is it >exclusive to the => syntax? > >Thanks.
If something can already be done in PHP then why the rush to complicate the language so that the same thing can be accomplished with slightly fewer keystrokes? The idea that you should reduce 'function' to 'fn' just to save 6 keystrokes strikes me as ludicrous. It also breaks one of the fundamental rules of programming which is "Programs must be written for people to read, and only incidentally for machines to execute." Replacing proper words with TLAs or even symbols will make the language less readable. It will also make it difficult for someone to spot a piece of unusual code and look it up in the manual to find out what it means. Those who want a language with hieroglyphic syntax should go back to Perl, but please leave PHP alone! Anybody who is in favour of such a bad move deserves to have their keyboard confiscated and to be sent to bed without any supper.
-- Tony Marston

Christoph Becker

9 years ago
On 03.02.2017 at 18:53, Levi Morrison wrote:
> One more thing: I'd like to re-emphasize that the syntax that > JavaScript uses and the one that HHVM/Hack uses are ambiguous in the > current class of our grammar. The following will not work unless we > move to a more powerful grammar and parser class: > > (params) => expr > (params) ==> expr
I'm not really familiar with re2c and bison, but I wonder why it's possible to distinguish expr > expr from expr -> expr then. Note that I'm not suggesting to use the Hack syntax here – I'm just curious.
-- Christoph M. Becker

Aaron Piotrowski

9 years ago
> On Feb 3, 2017, at 11:53 AM, Levi Morrison <levim@php.net> wrote: > > One more thing: I'd like to re-emphasize that the syntax that > JavaScript uses and the one that HHVM/Hack uses are ambiguous in the > current class of our grammar. The following will not work unless we > move to a more powerful grammar and parser class: > > (params) => expr > (params) ==> expr > > This is why an un-ambiguous prefix is necessary: the prefix breaks the > ambiguities. The syntax I have suggested in the RFC and the one I > suggested just now are not ambiguous because distinct prefixes: > > fn(params) => expr > |params| => expr > > I look forward to more discussion! > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php <http://www.php.net/unsub.php>
I personally prefer the `|params| => expr` syntax. I like the visual separation the syntax provides between auto-capturing, short closures and regular closures. It gives the impression that it should behave differently, rather than just being a shorter way of declaring a closure. Below are a couple of real-world single line closures using the proposed syntax: [1] Loop::defer(|| => ($this->when)($exception, $value)); [2] $this->watcher = Loop::delay($time, || => $this->resolve($value)); IMHO, the reduced boilerplate required makes it easier to discern what is happening. Regards, Aaron Piotrowski [1] https://github.com/amphp/amp/blob/master/lib/Coroutine.php#L45-L47 [2] https://github.com/amphp/amp/blob/master/lib/Pause.php#L21-L23

Yasuo Ohgaki

9 years ago
Hi Levi, On Sat, Feb 4, 2017 at 2:53 AM, Levi Morrison <levim@php.net> wrote:
> One more thing: I'd like to re-emphasize that the syntax that > JavaScript uses and the one that HHVM/Hack uses are ambiguous in the > current class of our grammar. The following will not work unless we > move to a more powerful grammar and parser class: > > (params) => expr > (params) ==> expr > > This is why an un-ambiguous prefix is necessary: the prefix breaks the > ambiguities. The syntax I have suggested in the RFC and the one I > suggested just now are not ambiguous because distinct prefixes: >
Thanks for explanation.
> an un-ambiguous prefix is necessary
This is what I guessed. This should be emphasized and everyone should understand. Otherwise, discussion goes nowhere.
> fn(params) => expr > |params| => expr > > I look forward to more discussion! >
It's unfortunate we cannot have HHVM/Hack syntax now https://docs.hhvm.com/hack/lambdas/introduction but both fn(params) => expr |params| => expr would be good enough for now. I don't see much problem with |(int | float) params| => expr It's better to be compatible with other implementations if it is possible. PHP may have HHVM/Hack syntax support in the future. Regards,
-- Yasuo Ohgaki yohgaki@ohgaki.net

Yasuo Ohgaki

9 years ago
On Sat, Feb 4, 2017 at 4:14 PM, Yasuo Ohgaki <yohgaki@ohgaki.net> wrote:
> >> fn(params) => expr >> |params| => expr >> >> I look forward to more discussion! >> > > It's unfortunate we cannot have HHVM/Hack syntax now > https://docs.hhvm.com/hack/lambdas/introduction > > but both > fn(params) => expr > |params| => expr > would be good enough for now. I don't see much problem with > |(int | float) params| => expr >
One question. Does the syntax allow chains? function chained_allow_func() { $f = |$x| => |$y| => $x + $y; $fn = $f(3); return $fn(2); // Returns 5 } It would be great if this is supported. Thanks.
-- Yasuo Ohgaki yohgaki@ohgaki.net

Larry Garfield

9 years ago
On 02/03/2017 11:53 AM, Levi Morrison wrote:
> >> Thanks to everyone who has participated in the discussion thus far. >> Primarily the feedback has been directed at the `fn` keyword. Let me >> provide two benefits and drawbacks of using `fn` as a keyword: >> >> 1. `fn` is searchable in search engines and in our manual >> 2. Is more intuitive than just syntax >> >> However, `fn` does have downsides: >> >> 1. Can break existing code >> 2. We already have a similar keyword `function` >> >> To that end, I'd like to gauge interest in a pure syntax based >> alternative that is similar to Rust and Ruby. >> Instead of: >> >> fn(params) => expr >> >> What about: >> >> |params| => expr >> >> This trades the advantages of the keyword for the advantages of pure >> syntax, and happens to be two characters shorter. To be explicit: >> >> 1. Preserves 100% backwards compatibility >> 2. Avoids having two keywords that both mean "function" >> 3. Is not easily searchable in engines or in the manual >> 4. Is a tad bit shorter >> >> What do you think, Internals? > One more thing: I'd like to re-emphasize that the syntax that > JavaScript uses and the one that HHVM/Hack uses are ambiguous in the > current class of our grammar. The following will not work unless we > move to a more powerful grammar and parser class: > > (params) => expr > (params) ==> expr > > This is why an un-ambiguous prefix is necessary: the prefix breaks the > ambiguities. The syntax I have suggested in the RFC and the one I > suggested just now are not ambiguous because distinct prefixes: > > fn(params) => expr > |params| => expr > > I look forward to more discussion!
Off hand, either of the above options would be acceptable to me. The union type concern is a valid one, but as noted I don't know how much of an issue that would be in practice even if we ever did get union types. (Now, if we also added defined type aliases... :-) ) I am definitely not a fan of reusing `function`. The way I see it, the point of a short-closure is to take a simple expression and wrap it into a function so that it can be plugged into a function context. I don't even think of it in the same way I would a named function/method, more casting an expression to a function. Additionally, to the point that was raised about developers being able to understand syntax reused in different context, that's true... if the context is in fact different. A bitwise AND and a reference are extremely different situations so there's no reason for my brain to expect both to mean the same thing. One is never a viable substitute for the other. In contrast, however, we're talking about two different syntaxes for defining anonymous functions that have different closure semantics. Reusing `function` would mean: $n = 2; $x = function ($a) use ($n) { return $a * $n; } $y = function ($a) => $a * $n; Are equivalent. But in order to know what the capture semantics are I can't tell from the start of the expression. I have to look halfway down the line to know what the behavior is going to be for these two extremely similar actions. In contrast: $n = 2; $x = function ($a) use ($n) { return $a * $n; } $y = fn($a) => $a * $n; $z = |$a| => $a * $n; I in versions $y and $z, I can tell right from the beginning of the line which variant of "anonymous function capture logic" I will be dealing with. I know from character 1 or 2, not character 12. And then there's the extra typing and visual space taken up, which is not something to dismiss entirely. Also, as someone else mentioned this syntax *seems* like it would support nesting. Compare the following: $x = function($a) => function($b) => function($c) => $a * $b * $c; $y = fn($a) => fn($b) => fn($c) => $a * $b * $c; $z = |$a| => |$b| => |$c| => $a * $b * $c; print $x(1)(2)(3); // prints 6 Which of these is more readable? Id' argue it's not $x. --Larry Garfield

Niklas Keller

9 years ago
2017-02-04 21:49 GMT+01:00 Larry Garfield <larry@garfieldtech.com>:
> On 02/03/2017 11:53 AM, Levi Morrison wrote: > >> >> Thanks to everyone who has participated in the discussion thus far. >>> Primarily the feedback has been directed at the `fn` keyword. Let me >>> provide two benefits and drawbacks of using `fn` as a keyword: >>> >>> 1. `fn` is searchable in search engines and in our manual >>> 2. Is more intuitive than just syntax >>> >>> However, `fn` does have downsides: >>> >>> 1. Can break existing code >>> 2. We already have a similar keyword `function` >>> >>> To that end, I'd like to gauge interest in a pure syntax based >>> alternative that is similar to Rust and Ruby. >>> Instead of: >>> >>> fn(params) => expr >>> >>> What about: >>> >>> |params| => expr >>> >>> This trades the advantages of the keyword for the advantages of pure >>> syntax, and happens to be two characters shorter. To be explicit: >>> >>> 1. Preserves 100% backwards compatibility >>> 2. Avoids having two keywords that both mean "function" >>> 3. Is not easily searchable in engines or in the manual >>> 4. Is a tad bit shorter >>> >>> What do you think, Internals? >>> >> One more thing: I'd like to re-emphasize that the syntax that >> JavaScript uses and the one that HHVM/Hack uses are ambiguous in the >> current class of our grammar. The following will not work unless we >> move to a more powerful grammar and parser class: >> >> (params) => expr >> (params) ==> expr >> >> This is why an un-ambiguous prefix is necessary: the prefix breaks the >> ambiguities. The syntax I have suggested in the RFC and the one I >> suggested just now are not ambiguous because distinct prefixes: >> >> fn(params) => expr >> |params| => expr >> >> I look forward to more discussion! >> > > Off hand, either of the above options would be acceptable to me. The union > type concern is a valid one, but as noted I don't know how much of an issue > that would be in practice even if we ever did get union types. (Now, if we > also added defined type aliases... :-) ) > > I am definitely not a fan of reusing `function`. The way I see it, the > point of a short-closure is to take a simple expression and wrap it into a > function so that it can be plugged into a function context. I don't even > think of it in the same way I would a named function/method, more casting > an expression to a function. > > Additionally, to the point that was raised about developers being able to > understand syntax reused in different context, that's true... if the > context is in fact different. A bitwise AND and a reference are extremely > different situations so there's no reason for my brain to expect both to > mean the same thing. One is never a viable substitute for the other. > > In contrast, however, we're talking about two different syntaxes for > defining anonymous functions that have different closure semantics. Reusing > `function` would mean: > > $n = 2; > > $x = function ($a) use ($n) { return $a * $n; } > $y = function ($a) => $a * $n; > > Are equivalent. But in order to know what the capture semantics are I > can't tell from the start of the expression. I have to look halfway down > the line to know what the behavior is going to be for these two extremely > similar actions. >
I'd say the capture semantics aren't the first thing to be concerned with. First you want to know it's a anonymous function with one parameter, exactly what "function ($a)" tells you. For normal closures, "use ($n)" tells you it imports $n from the parent scope into the body enclosed in braces. For short closures, you see the "=>" and an expression and know that any outer variable you use will be imported from the parent scope. Regards, Niklas

Levi Morrison

9 years ago
> And then there's the extra typing and visual space taken up, which is not > something to dismiss entirely. Also, as someone else mentioned this syntax > *seems* like it would support nesting. Compare the following: > > $x = function($a) => function($b) => function($c) => $a * $b * $c; > $y = fn($a) => fn($b) => fn($c) => $a * $b * $c; > $z = |$a| => |$b| => |$c| => $a * $b * $c; > > print $x(1)(2)(3); // prints 6 > > Which of these is more readable? Id' argue it's not $x.
In a past version the RFC included an example of chaining. The current version doesn't show an example, but does say it is possible. To be clear: $x = fn($a) => fn($b) => fn($c) => $a * $b * $c; Is supported in the current implementation. It would similarly be supported in the `|params| => expr` notation.

Rasmus Schultz

9 years ago
I'd strongly prefer a syntax without the introduction of "fn" keyword - e.g. similar to closures in other languages. I also feel that there's a feature missing - something that was possible with closures: $total = 0; $add = function ($value) use (&$total) { $total += $value; }; Per the RFC:
> When a variable in the expression is defined in the parent scope it will
be captured implicitly by-value Whether you regard it as a good thing or bad thing (I'm only pointing it out) this is inconsistent with JavaScript, where variables in the parent scope are captured by-reference. If we're introducing a new form and syntax for closures, why not make this one align with something that's going to be familiar with developers? That's just my opinion, but whether you agree with that or not - as long as we're introducing a new form and syntax, why make it *less* capable than ordinary PHP closures? At the very least, I feel there should be feature parity - otherwise, code in the wild is going to continue to be a strange mess of one form or the other, which doesn't help with language comprehension at all, especially when both forms also work differently from JavaScript closures, which are likely the form of closures that web-developers are going to be most familiar with. Don't get me wrong, I'm not saying "make it like JavaScript" - what I'm saying is, make something that is familiar to developers *somehow*, e.g. either provide feature parity with ordinary PHP closures and make it familiar to PHP developers, *or* make it similar to JavaScript closures, but don't throw yet another "original" idea on the pile. Ultimately, I think what I'd like to see would be something along the lines of this: $total = 0; $add = ($value) => { &$total += $value; }; That is: - Lose the fn keyword - get the syntax down to something similar to closures in most other languages. - Keep it working like PHP (which you intend to do anyhow) in terms of importing variables by-value. - Provide feature parity with regular PHP closures by providing some means of accessing variables by-reference. I understand that the fn keyword is there to remove ambiguities, but I think working around the ambiguities is possible, even if it's difficult - there was ambiguity with < and > operators in the run-of-the-mill generics syntax I proposed last year, and Dominic Grostate was able to work through them and get it to parse after all. I understand it's probably difficult, and it may not be possible to achieve something that is 100% technically correct, but it's usually possible to achieve something that works for almost any real-world use-case. The last thing I would comment on is multi-statement bodies. Omitting this is, in my opinion, a very bad decision - it will, again, lead to lack of feature parity with regular closures, which will mean, in practice, factoring back and forth between regular closures and fat arrow functions, which will be frustrating. It will also encourage developers to attempt to fold complex operations into a single expression, leading to further frustration for the programmer, and unreadable code for collaborators, because "damnit I'm not going back to regular closures!", right? In my opinion, if you can't provide feature parity on these points with regular closures, this feature will hurt more than help - it will lead to a lot of meaningless struggles, unreadable code, and code that doesn't refactor well, and, eventually, BC breaks when PHP 7.x finally does introduce these missing features. On Mon, Jan 30, 2017 at 6:55 PM, Levi Morrison <levim@php.net> wrote:

Rowan Collins

9 years ago
On 30/01/2017 17:55, Levi Morrison wrote:
> Here is an example of an existing closure: > > function ($x) use ($arr) { > return $arr[$x]; > } > > This RFC proposes syntax and semantics to simplify this common usage to: > > fn($x) => $arr[$x]
I think a lot of the disagreements and confusions on this thread come down to there being three fundamental views of what this new syntax is for: (a) an improved syntax for declaring closures (in the way that [$foo, $bar] is a shorter syntax for array($foo, $bar)) (b) improved *semantics* for declaring closures, where you don't have to list the variables to be captured (c) a new kind of closure designed for specific use cases, with its own syntax and semantics These aren't mutually exclusive aims, but which of them you have in mind makes a big difference to what you see as "better" or "worse". Many of those starting from view (a) or (b) would like to see the syntax extended to closures with full bodies, and perhaps eventually become the most common way of declaring closures. Even if not included initially, they want to design the feature with that in mind. From view (c), the syntax is expected to exist alongside existing closures forever, just as we have both "for" and "while" loops. For the record, I generally come from view (c). On 05/02/2017 11:10, Rasmus Schultz wrote:
> as long as we're introducing a new form and syntax, why make it*less* capable than > ordinary PHP closures?
This is a good summary of the natural position from view (a) or (b) - if this is going to be the new way of declaring closures, we should make it the best way of declaring closures. If it was just about making the syntax shorter, this would be fine - like [...] for array(...) - but the Big Idea here is automatic capture of variables, and that is a lot more than just a nicety of syntax. As Rasmus L. has pointed out, making automatic variable capture the norm would be a huge change in how PHP defined variable scope. Since the comparison to JS keeps coming up, consider this: in JS, *all* functions capture scope greedily when they're declared; in PHP, *no* functions capture scope automatically; the use() clause maintains that rule for anonymous functions, and (in my opinion) that is a feature, not a mistake that needs fixing.
> At the very least, I feel there should be feature > parity - otherwise, code in the wild is going to continue to be a strange > mess of one form or the other, which doesn't help with language > comprehension at all
To be clear, from view (c), there is absolutely nothing "strange" or "messy" about future code having both closures and arrow-functions; they are different tools, to be used in different circumstances. On 04/02/2017 07:40, Stephen Reay wrote:
> So, is there any argument besides "6 more characters" for*not* using the function keyword?
This question presumably comes from view (b) - if it's just another way of declaring a function, why do we need a new keyword? From view (a), those 6 more characters are enough argument in themselves, because if the aim is to make it shorter, why stop early? From view (c), the fact that the keywords are different is a feature not a bug - these aren't functions in the normal sense, they are a new way of defining a callable, so they *should* look different. On 04/02/2017 20:49, Larry Garfield wrote:
> The way I see it, the point of a short-closure is to take a simple > expression and wrap it into a function so that it can be plugged into > a function context. I don't even think of it in the same way I would > a named function/method, more casting an expression to a function.
This, meanwhile, is a good summary of view (c), and expresses my view better than I could myself. If anything, I agree that "fn" is *too much* like "function"; perhaps we should find something *more* distinct, like "lambda" ($foo = lambda($x) => $x * 2). That would have the advantage of giving a proper name to these new callables, and make them easier to discuss: "when your callback is too complex for a lambda, use a closure". Obviously that would imply permanently cutting off all chance of full function bodies with auto capture. Personally, I think that's a good thing, but I realise not everyone agrees. In short, remember that something that is "obviously better" for you may be "obviously worse" for someone else, simply because you are measuring against different aims. Regards,
-- Rowan Collins [IMSoP]

Ilija Tovilo

9 years ago
Hey everyone I’m on team C as well. One complaint about the RFC is that it doesn’t support multi-statement bodies. Arrow functions are especially useful for functional programming where it’s common to return a value in a single expression. Using multiple statements (partly) destroys the usefulness of the arrow function as that would require a `return` keyword, braces and semicolons. Additionally, long closures with multiple statements may actually benefit from not implicitly capturing variables from the outer scope, especially since in PHP there’s no keyword to declare your variables, which might lead to you accidentally capturing a variable instead of creating a new one. This isn’t as much of a problem with arrow functions as assignments are much less useful when you’re limited to a single expression. Thus it might be best to use each when most appropriate. @Levi, @Bob Just out of curiosity, are variables captured by value for a specific reason? Would there be any limitations capturing the variables by reference? And also, have you considered letting people vote for their preferred arrow function syntax? I kinda don’t think we’re gonna find an agreement as there are so many different opinions. Regards, Ilija On 5 Feb 2017, 18:52 +0100, Rowan Collins <rowan.collins@gmail.com>, wrote:

Rowan Collins

9 years ago
Hi Ilija, On 7 February 2017 18:58:15 GMT+00:00, ilija.tovilo@me.com wrote:
>And also, have you considered letting people vote for their preferred >arrow function syntax? >I kinda don’t think we’re gonna find an agreement as there are so many >different opinions.
The problem with voting on alternative syntaxes is precisely that there *are* so many different options. Designing a vote with multiple options that gives an answer people are happy with is a whole science in itself. I think the best we can do is have a "without prejudice" vote on a single proposal - if it is declined, a new proposal can be made after a suitable period of reflection. This has already happened once with this very topic, this RFC having emerged from a previous one being rejected. That doesn't mean we can't discuss other syntaxes, but just opening up all possible options to a vote doesn't really help IMHO. Regards,
-- Rowan Collins [IMSoP]

Ilija Tovilo

9 years ago
Hi Rowan I see. I still think a simple poll would be useful to choose the least controversial syntax. Otherwise I fear that the RFC might get rejected out of superficial reasons. Regards, Ilija On 7 Feb 2017, 21:07 +0100, Rowan Collins <rowan.collins@gmail.com>, wrote:

Björn Larsson

9 years ago
Den 2017-03-24 kl. 21:08, skrev ilija.tovilo@me.com:
> Hi Rowan > > I see. I still think a simple poll would be useful to choose the least controversial syntax. > Otherwise I fear that the RFC might get rejected out of superficial reasons. > > Regards, > Ilija > > > On 7 Feb 2017, 21:07 +0100, Rowan Collins <rowan.collins@gmail.com>, wrote: >> Hi Ilija, >> >> On 7 February 2017 18:58:15 GMT+00:00, ilija.tovilo@me.com wrote: >>> And also, have you considered letting people vote for their preferred >>> arrow function syntax? >>> I kinda don’t think we’re gonna find an agreement as there are so many >>> different opinions. >> The problem with voting on alternative syntaxes is precisely that there *are* so many different options. Designing a vote with multiple options that gives an answer people are happy with is a whole science in itself. >> >> I think the best we can do is have a "without prejudice" vote on a single proposal - if it is declined, a new proposal can be made after a suitable period of reflection. This has already happened once with this very topic, this RFC having emerged from a previous one being rejected. >> >> That doesn't mean we can't discuss other syntaxes, but just opening up all possible options to a vote doesn't really help IMHO. >> >> Regards, >> >> -- >> Rowan Collins >> [IMSoP] >> >> -- >> PHP Internals - PHP Runtime Development Mailing List >> To unsubscribe, visit: http://www.php.net/unsub.php >>
Hi, My suggestion for a vote would be: - Vote about the feature. - Vote about syntax if no consensus can be reached. My suggestion would be to both have a short and long version: - |params| => expr - lambda(params) => expr An example where one have two syntaxes for same feature is the jQuery library, i.e. $() and jQuery(). I plan to read up on the RFC once more this week regarding the feature itself. Any plans to go with this for 7.2? Regards //Björn Larsson

Levi Morrison

9 years ago
> Any plans to go with this for 7.2?
I have been working on this RFC a bit in the last two weeks and intend to start voting within the next week.

Björn Larsson

9 years ago
Den 2017-04-05 kl. 23:57, skrev Levi Morrison:
>> Any plans to go with this for 7.2? > I have been working on this RFC a bit in the last two weeks and intend > to start voting within the next week. >
Great, I look forward to reading the updated RFC :) Will you include both a short- and longhand version of the syntax or only one? Regards //Björn Larsson