Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:88602 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 312 invoked from network); 1 Oct 2015 11:52:12 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 1 Oct 2015 11:52:12 -0000 Authentication-Results: pb1.pair.com header.from=morrison.levi@gmail.com; sender-id=pass Authentication-Results: pb1.pair.com smtp.mail=morrison.levi@gmail.com; spf=pass; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 209.85.213.53 as permitted sender) X-PHP-List-Original-Sender: morrison.levi@gmail.com X-Host-Fingerprint: 209.85.213.53 mail-vk0-f53.google.com Received: from [209.85.213.53] ([209.85.213.53:35896] helo=mail-vk0-f53.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id F5/B4-04700-B6E1D065 for ; Thu, 01 Oct 2015 07:52:11 -0400 Received: by vkfp126 with SMTP id p126so38125271vkf.3 for ; Thu, 01 Oct 2015 04:52:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:sender:in-reply-to:references:date:message-id:subject :from:to:cc:content-type:content-transfer-encoding; bh=40s8fGK8ie8GMYwHffE9lOdwq0OhZCNOJmzJAh1kxjI=; b=aeNj2FbuXSZXeYMAxTkLbFqqFPuBuR2VGPoaagn8CdQwWAeSzs/tVCDrUFEPrRaHEg kNUo5p0xRjPaH+mwInx5Ce/neJi51vPF2kQvnBsYMgnHvZRjyB8nkqs76rnHmxbXffg9 PWHKpLMQolbRiYZ4Wm/AYL/BW391vNhbimbiy21/RhLeLl29FnbKYUFOExcL2skOO+RV sfTBumbzWo8Or0VYZTqzgX678MVHFCeJM7102oeWogoZ3lhx3R28okYseLNjEwx3Dlfa UUfmHdv+Aq0q46Q/zUECGJAyifhOqkgU9sWtjMwi+kmbLIRK8VG4dz6y0x4U+xHUNd5b yKlQ== MIME-Version: 1.0 X-Received: by 10.31.158.213 with SMTP id h204mr6280971vke.48.1443700328369; Thu, 01 Oct 2015 04:52:08 -0700 (PDT) Sender: morrison.levi@gmail.com Received: by 10.31.41.205 with HTTP; Thu, 1 Oct 2015 04:52:08 -0700 (PDT) In-Reply-To: References: Date: Thu, 1 Oct 2015 05:52:08 -0600 X-Google-Sender-Auth: Xk9Is3N5vZjGA4-iCWLmpIpt9SU Message-ID: To: Stephen Coakley Cc: internals Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: Re: [PHP-DEV] Re: Arrow function expressions in PHP From: levim@php.net (Levi Morrison) On Wed, Sep 30, 2015 at 11:59 PM, Stephen Coakley w= rote: > On 09/26/2015 11:17 AM, Levi Morrison wrote: >> >> (Email in gist format: >> https://gist.github.com/morrisonlevi/fa7984c04ff176b5a87c) >> >> In EcmaScript 2015 (ES6) the expression `(x) =3D> x * 2` means to create >> an anonymous function with one parameter `x` that will return `x * 2`. >> For example: >> >> (x) =3D> 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 =3D [ >> "Hydrogen", >> "Helium", >> "Lithium", >> "Beryl=C2=ADlium" >> ]; >> >> var a2 =3D a.map(function(s){ return s.length }); // pre-ES6 >> >> var a3 =3D a.map((s) =3D> 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 functio= n >> [($x) =3D> $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) =3D> $x * 2; >> >> This is why Bob Weinand [proposed][2] using `~>` instead of `=3D>`. >> However, if we allow type declarations there is another issue. In the >> definition `(Type &$x) =3D> expr` the `(Type &$var)` part can parse as >> "take constant `Type` and variable `$var` and do a bitwise and `&` >> operation." After that the `=3D>` 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 `=3D>` to `~>` doesn't affect this issue. >> >> We could solve the first ambiguities with prefering the current >> meaning with `key =3D> 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) =3D> $x * 2]; >> >> // clearly yields an anonymous function >> yield function($x) =3D> $x * 2; >> >> // clearly an anonymous function >> function(Type &$x) =3D> 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) =3D> 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) =3D> $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`. >> >> What concerns do you have about `fn($x) =3D> $x * 2` or `function($x) = =3D> >> $x * 2`? I will be writing a proper RFC later but I wanted to get >> discussion going now. >> >> [1]: >> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functi= ons/Arrow_functions >> [2]: https://wiki.php.net/rfc/short_closures >> > > If my opinion is worth anything, I actually like how fn($x) =3D> $x * 2 l= ooks > the most. It's fairly short like the original proposal, but has the > advantage of *clearly* appearing to be a function. That was a large > complaint on the whole "short closures" idea in the first place, and PHP > usually does a good job at making code very obvious and clear. > > So yeah, an "fn" prefix (and requiring parenthesis always) looks very > consistent, but still is short. > >> I would prefer that we shorten the `function` keyword to `fn`: > > Do you mean generally, or just in short closures? Turning the keyword > everywhere would be a huge BC break (though pretty easy to fix in code: > "s/function\s/fn /g" :-) ). I'd be OK with allowing both everywhere for > consistency though: > > fn square(int $x) { > return $x * $x; > } > > $squaresPlusOne =3D array_map(function(int $x) =3D> square($x) + 1, [= 1, 2, > 3, 4]); > > class Foo { > public fn __construct() {} > } > > You get the idea... > > I actually really like that + your idea. Kudos. I am definitely not proposing to remove `function` at this time. That would be a huge BC break, indeed! I meant only that `fn` can be used for brevity if that is preferred and it *could* be used in other places as well. This is my preference, but I know other people don't like that, which is why I would intend to keep it as a separate vote from the arrow part (=3D> expr).