Re: Arrow function expressions in PHP
| From: | Levi Morrison | Date: | Mon, 28 Sep 2015 22:52:39 +0000 |
| Subject: | Re: Arrow function expressions in PHP | ||
| References: | 1 2 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-88536@lists.php.net to get a copy of this message | ||
On Mon, Sep 28, 2015 at 3:38 PM, Pavel Kouřil <pajousek@gmail.com> wrote:
> On Sat, Sep 26, 2015 at 6:17 PM, Levi Morrison <levim@php.net> wrote:
>> (Email in gist format:
>> https://gist.github.com/morrisonlevi/fa7984c04ff176b5a87c)
>>
>> In EcmaScript 2015 (ES6) the expression
(x) => x * 2
>> means to create
>> an anonymous function with one parameter x that will return
>> x * 2.
>> For example:
>>
>> (x) => x * 2
>> // is equivalent to:
>> function(x) { return x * 2; }
>>
>> A modified example from [documentation by Mozilla Developer
>> Network][1] page demonstrates how they are useful:
>>
>> var a = [
>> "Hydrogen",
>> "Helium",
>> "Lithium",
>> "BerylÂlium"
>> ];
>>
>> var a2 = a.map(function(s){ return s.length }); // pre-ES6
>>
>> var a3 = a.map((s) => s.length); // ES6
>>
>> There has been some talk about how we can use arrow function
>> expressions in PHP. In PHP using the same syntax would have some
>> ambiguities:
>>
>> // Does this mean:
>> // 1. Create an array key with the result of ($x) and
>> a value
>> with $x * 2
>> // 2. Create an array with one value that is an anonymous function
>> [($x) => $x * 2]
>>
>> // Does this mean:
>> // 1. Yield a key with the result of ($x) and a value
>> with $x * 2
>> // 2. Yield an anonymous function
>> yield ($x) => $x * 2;
>>
>> This is why Bob Weinand [proposed][2] using ~> instead
>> of =>.
>> However, if we allow type declarations there is another issue. In the
>> definition (Type &$x) => expr the
>> (Type &$var) part can parse as
>> "take constant Type and variable
>> $var and do a bitwise and &
>> operation." After that the => will be an unexpected
>> token. Even
>> though the rule would be invalid the parser doesn't know that far
>> ahead it will error and it doesn't know which rule to pick. Changing
>> the token from => to
>> ~> doesn't affect this issue.
>>
>> We could solve the first ambiguities with prefering the current
>> meaning with key => value and requiring the meaning with
>> closures to
>> wrap them in (). We could solve the latter ambiguity with a
>> backtracking parser since it will eventually error and then know to
>> pick the other rule. However, I really think this is a bad idea.
>>
>> So how can we have shorter closures without this mess? One simple way
>> is to require the function prefix:
>>
>> // clearly an array with an anonymous function
>> [function($x) => $x * 2];
>>
>> // clearly yields an anonymous function
>> yield function($x) => $x * 2;
>>
>> // clearly an anonymous function
>> function(Type &$x) => expr;
>>
>> Requiring the function prefix mitigates one of the value
>> parts of
>> arrow functions: they are short.
>>
>> Another option would be to resolve the ambiguities with keys and
>> values but to change the type information in parameters:
>>
>> (&$input: array) => expr
>>
>> By putting the type after the variable (similar to how we declare
>> return types) we no longer have the issues with mis-parsing. Of
>> course, that's not how we declare parameter types currently. I think
>> we would need to permit it everywhere and deprecate the current syntax
>> with the type being prefixed. (By deprecate I mean in PHP 8 and not
>> remove it until PHP 9 or later)
>>
>> I would prefer that we shorten the function keyword to
>> fn:
>>
>> [fn($x) => $x * 2]
>>
>> This preserves the shortness of the expression while providing
>> unambiguous, simple parsing. Of course, now we have a similar issue:
>> we have both fn and functionú2ô3°iÏæM“^9²6
>> .
>>
>> What concerns do you have about fn($x) => $x * 2 or
>> `function($x) =>
>> $x * 2`? I will be writing a proper RFC later but I wanted to get
>> discussion going now.
>>
>> [1]: ‡¦ºáÙƒW²…[iœ‹
>> ;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
>> [2]: https://wiki.php.net/rfc/short_closures
>>
>> --
>> PHP Internals - PHP Runtime Development Mailing List
>> To unsubscribe, visit: http://www.php.net/unsub.php
>>
>
>
> Hello,
>
> personally, as a purely userland dev, I feel that the correct syntax
> would be the "simplest" one - and that's imho the (Type &$x) ==> expr
>
> Or the version with ~> operator - I don't care which one gets in,
> althought I would rather see the ==> one. :)
>
> I understand that there might be some ambiguity in the parser that
> would need to be solved by backtracking, but for using the language,
> the "simplest" option should IMHO be the correct one. Also not
> introducing any more "stuff" (like new parameter types syntax) would
> be a plus.
>
> For the need to have a single parameter enclosed with ( ) - by
> thinking more and more about it, I think that having the one special
> case for not requiring parenthesis around parameters is pretty uselss,
> since it would have to be there anyways if you wrote the typehint.
I do not think it is feasible to make the parser do backtracking or
anything of that sort. How do others feel?
> PS: the [fn($x) => $x * 2] seems ambigous, from reader's POV; key of
> the item is result of fn($x) and value is $x * 2? Also, it would be a
> huge BC break with not allowing you to name functions fn(), wouldn't
> it?
This is not a huge backwards compatibility break, no. It is a small
break. This is one reason fn is not necessarily what I will be
proposing and want to hear more feedback. Note that the function
version wouldn't be possible to be confused *at all*:
// function($x) isn't allowed for function name
// so this is very unambiguous
[function($x) => $x * 2];
Also note that using closures in array literals is not really that common.