Re: [RFC] Arrow functions / short closures
| From: | Nikita Popov | Date: | Thu, 14 Mar 2019 09:26:41 +0000 |
| Subject: | Re: [RFC] Arrow functions / short closures | ||
| References: | 1 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-104710@lists.php.net to get a copy of this message | ||
On Wed, Mar 13, 2019 at 4:56 PM Nikita Popov <nikita.ppv@gmail.com> wrote:
> Hi internals,
>
> Motivated by the recent list comprehensions RFC, I think it's time we took
> another look at short closures:
>
> https://wiki.php.net/rfc/arrow_functions_v2
>
> This is based on a previous (withdrawn) proposal by Levi & Bob. It uses
> the syntax
>
> fn($x) => $x * $multiplier
>
> and implicit by-value variable binding. This example is roughly equivalent
> to:
>
> function($x) use($multiplier) { return $x * $multiplier; }
>
> The RFC contains a detailed discussion of syntax choices and binding modes.
>
Trying to reply to everyone in one mail...
1. Using f() =>. This is possible. However, f would become a reserved
keyword, and I'm very leery of making a single-character reserved keyword.
Additionally I think that the fn() => syntax is more intuitive, but maybe
that's my Rust influences speaking ;)
2. $this binding. Yes, $this is indeed bound exactly as with normal
closures. I've explicitly mentioned this in the RFC now.
3. yield. Using yield is per-se not a problem. You can write `() => yield
42
, which is basically function() { return yield 42; }`, which is okay,
because yield is an expression and generators can return values since PHP
7. It also doesn't seem particularly useful though, as you're limited to
yielding a single value.
However, in the current form short closures are a replacement for list
comprehensions only insofar they make the use of map() and filter()
non-torturous. You couldn't actually use them to get a comprehension-like
syntax as suggested in the other thread:
$gen = (fn() => foreach ($list as $elem) yield $elem * 2))();
// would be, hypothetically:
$gen = (function() use($list) { return foreach ($list as $elem) yield
$elem * 2; }))();
The yield part here isn't the problem, "return foreach" is. Unlike yield,
foreach is a statement, not an expression. To make this work we'd need a
block form of short closures:
$gen = (fn() { foreach ($list as $elem) yield $elem * 2; })();
// or maybe
$gen = (fn() => { foreach ($list as $elem) yield $elem * 2; })();
Either way, I wouldn't want to read that code ;) The right way to write
this is $list->map(fn($elem) => $elem * 2).
4. ($x) => $x instead of $x => $x. As Rowan mentioned, this doesn't really
change things. Where $x is valid, ($x) is in most cases also valid.
Regards,
Nikita