Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:88515 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 24034 invoked from network); 26 Sep 2015 16:58:29 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 26 Sep 2015 16:58:29 -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.44 as permitted sender) X-PHP-List-Original-Sender: morrison.levi@gmail.com X-Host-Fingerprint: 209.85.213.44 mail-vk0-f44.google.com Received: from [209.85.213.44] ([209.85.213.44:33516] helo=mail-vk0-f44.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 63/B1-06395-4BEC6065 for ; Sat, 26 Sep 2015 12:58:28 -0400 Received: by vkgd64 with SMTP id d64so71878230vkg.0 for ; Sat, 26 Sep 2015 09:58:26 -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:content-type:content-transfer-encoding; bh=0di1+RoCBQxCPXS7/BqRktfp3nJzA7ZDM7ahUl0cUWA=; b=C/9X+46q2JQGQuN9qVpuuz3dVoqApivywNh3DhQK+RUnZb1xjOYHXh607886m9Nwab EKM1VlmHaDscil743XGXZiovmo6NmHMNKFyz+bE6HvcUnFqbPeHgNgfHjpYy//d5Xbvd dRzAHk1CP/0o4IoiNkH9ZPi0JzGm/YbSBhv8bSZO05BdNMLwTXfxliN9dCmzazSK4UPC cKM278qaHXta/SIMRyEo3A750i2c5/iy6+1DmIMuAXdZbMaiMhyegC35QEdMC4njslg0 qJOvCGpI9WEeNihNwSOrt9Ht7VkkGXPpgqSxM0aGji8vo17g0Nc4XCaMZ5Xj1kwlleLx SMvg== MIME-Version: 1.0 X-Received: by 10.31.163.75 with SMTP id m72mr7194374vke.54.1443286705996; Sat, 26 Sep 2015 09:58:25 -0700 (PDT) Sender: morrison.levi@gmail.com Received: by 10.31.41.205 with HTTP; Sat, 26 Sep 2015 09:58:25 -0700 (PDT) In-Reply-To: References: Date: Sat, 26 Sep 2015 10:58:25 -0600 X-Google-Sender-Auth: zw4cpwwsEG5XFEvvXpkc_fdTx9M Message-ID: To: internals Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: Re: Arrow function expressions in PHP From: levim@php.net (Levi Morrison) On Sat, Sep 26, 2015 at 10: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 function > [($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/= Functions/Arrow_functions > [2]: https://wiki.php.net/rfc/short_closures I forgot to mention that the arrow expressions would close over any values that exist in their parent scope. Like Bob's proposal this happens by value (in fact the draft I have for it simply replaces the parser and reuses his implementation): function add($x) { return fn($y) =3D> $x + $y; } add(1)(2); // int(3)