Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:111999 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 11005 invoked from network); 5 Oct 2020 01:28:56 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 5 Oct 2020 01:28:56 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id A62BD1804B3 for ; Sun, 4 Oct 2020 17:41:52 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE autolearn=no autolearn_force=no version=3.4.2 X-Spam-Virus: No X-Envelope-From: Received: from mail-qv1-f50.google.com (mail-qv1-f50.google.com [209.85.219.50]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Sun, 4 Oct 2020 17:41:51 -0700 (PDT) Received: by mail-qv1-f50.google.com with SMTP id w5so1076200qvn.12 for ; Sun, 04 Oct 2020 17:41:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=newclarity-net.20150623.gappssmtp.com; s=20150623; h=mime-version:subject:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to; bh=QoJlTMhuFZ9fAfQbej3tK0i7zjLJGyVUKTxYlxzbjzg=; b=mjMl/x57AnjhiE64FQHBIlUh29Ge2WHVg9QJmytN4tyeUd6QZQJsyOtcvxbZCOoCBN ne3Ze2Nb/QY9uQ3fQYmcUQKR/t75N23LniaH6craOBGttnI0FKxBzdAbNW5ixoAH9xO4 Vad4YCwXkVzJO9Kx4MUgXmeG7f0y1WqUClqwLr8mtAvzad31D+/z49+SC677XWTjmFjG /K8tO8y4wIRfT0r/TllCwK4JRjnyMaKa6212vkzPNg7nDZ5d9ZYuL1tlD5jg/tLuFM/B cjjdcPPn0FNih+cEtOscmwVPGYn+A2UZpNTa8mAR2He8w1U9nBg51UdOfRUQS5vSg3TY XyxQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:subject:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to; bh=QoJlTMhuFZ9fAfQbej3tK0i7zjLJGyVUKTxYlxzbjzg=; b=Akjps83I993p5mAmpw0CIwI0ei0fbgOJU17RTXBm3/LmJ7MAL181ML8qO+4j3MD9YI yjTBbC6C59dI8CF7vPQnIzI2XU8s3lBaqpV5Zc/GgKgMrAAmvIbqb0QpcCFOlmZtox0F 5HprkMoZJiiMWvaBFjmk7QqGh1fHahJKfGHOzXra9N9vcJtRqrC0Pa0GgkAAa/hcM6xr 1fCuaLGTcKPcODsDgVLk+1EttopZ76K+o4LNtIzEfIpyzAcyPnvKGHGZGzagVQbEReQs qZcbrjaJXhAWBJPm3CKAqa/k7cnKnePo3QXyxbOIlFceN2e08JL3u9oqUY9sKVH148Bh CByQ== X-Gm-Message-State: AOAM53137y26EvDd84QrTYpoiw0tXCz+NTD5IwLAhfB4jwUvZvQ6aeT5 kYhxXj75mFbeqTO7FeDbBvVJhA== X-Google-Smtp-Source: ABdhPJw339iqu228+oVzAUrjSfY8DQmcIKxf5sCL4oTLrndqDUx84NERYlVHPcjIFWn+WSzIydN+AA== X-Received: by 2002:a0c:e5cf:: with SMTP id u15mr12360648qvm.14.1601858504908; Sun, 04 Oct 2020 17:41:44 -0700 (PDT) Received: from [192.168.1.254] (c-24-98-254-8.hsd1.ga.comcast.net. [24.98.254.8]) by smtp.gmail.com with ESMTPSA id y22sm6293671qki.33.2020.10.04.17.41.42 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 04 Oct 2020 17:41:43 -0700 (PDT) Content-Type: text/plain; charset=utf-8 Mime-Version: 1.0 (Mac OS X Mail 13.4 \(3608.120.23.2.4\)) In-Reply-To: <446c9894-191f-e53b-4534-31c4e7b91d7b@gmail.com> Date: Sun, 4 Oct 2020 20:41:41 -0400 Cc: internals@lists.php.net Content-Transfer-Encoding: quoted-printable Message-ID: References: <446c9894-191f-e53b-4534-31c4e7b91d7b@gmail.com> To: Rowan Tommins X-Mailer: Apple Mail (2.3608.120.23.2.4) Subject: Re: [PHP-DEV] RFC: Support for multi-line arrow functions From: mike@newclarity.net (Mike Schinkel) > On Oct 4, 2020, at 4:08 PM, Rowan Tommins = wrote: >=20 > Hi Nuno, >=20 > On 03/10/2020 22:09, Nuno Maduro wrote: >> A few days ago I opened a pull request that adds support for = multi-line >> arrow functions in PHP: https://github.com/php/php-src/pull/6246. >=20 >=20 > Welcome to the list. Firstly, it's probably worth having a look in the = mailing list archives for prior discussions on this, as it was = definitely discussed during the earlier short closures RFCs (the = successful one that gave us fn()=3D>expr, and a couple of earlier = attempts with different syntax and features). >=20 >=20 > Secondly, I'd like to point out that "short closures" actually have = three fundamental features: >=20 > 1. They have an implicit "return", making them ideal for single = expressions rather than blocks of procedural code. > 2. They automatically capture all variables in scope, rather than = having to import them with "use". > 3. They are shorter than normal closure declarations, both because of = the above two features, and because "fn" is slightly shorter than = "function". >=20 > I think it's worth making clear which of those three features we are = hoping to retain by combining arrow functions with blocks. >=20 >=20 > Feature 1 doesn't extend to code blocks in an obvious way. In some = languages, every statement is a valid expression, so you can place an = implicit "return" before the last statement of a block. In PHP, that's = not the case, so e.g. { $x =3D 'Hello World; echo $x; } cannot be = converted to { $x =3D 'Hello World; return echo $x; }. Alternatives = include converting to { $x =3D 'Hello World; echo $x; return null; } or = requiring all closure blocks to end with a valid expression. >=20 >=20 > Feature 2 is probably the one most people actually want extended, but = in my opinion is also the part most in need of justification, because it = changes the language quite fundamentally. >=20 > There are currently very few places in PHP where the scope of a = variable is not to the current function: properties of the current = object must be accessed via $this, and class properties via self:: or = similar; globals must be imported via a "global" statement, statics via = a "static" statement, and closed-over values via the "use" keyword. (The = main exception to this rule is the half-dozen built-in "superglobals"; I = think there are a few more obscure cases.) >=20 > In a single-expression closure, as currently allowed, there is limited = possibility for ambiguous scope. Extending this to function bodies of = any size leads to much more risk of complexity and confusion. >=20 > If you want to capture variables $a, $b, and $c, but have local = variables $x, $y, and $z, you would currently write this: >=20 > $f =3D function() use ($a, $b, $c) { > // $x, $y, $z must be local, because not imported > } >=20 > If we added an opt-in syntax for "capture everything", we might = instead write this: >=20 > $f =3D function() use (*) { > $x =3D $y =3D $z =3D null; > } >=20 > Without re-initialising all local variables, we would no longer be = able to know if they were actually local without looking at the = surrounding scope for a value that might be captured. I am unconvinced = by this trade-off of opt-out instead of opt-in. >=20 > One use case I've seen proposed is closures which capture a large = number of variables; I would be interested to see an example where this = is the case and is not a "code smell" in the same way as requiring a = large number of parameters. >=20 > In the above example I deliberately did not use the "fn()=3D>" syntax, = because I believe this is really orthogonal to the other features - my = impression is that actual expression length (feature 3 above) is more of = a pleasant side-effect than a top priority for most people. >=20 > I would personally prefer the "fn()=3D>" syntax to carry on meaning = "this is an expression elevated to function status", and have some other = syntax for a full closure that uses auto-capturing scope rules if that = feature is indeed needed. Good analysis. I agree #2 is the strongest motivator for some kind of improvement / = change. =20 In at least one prior language I have used there was no distinction = between local scope inside and outside of a closure, so when I first = realized I had to use the "use" clause to make variable visible it was = surprising to me. In PHP I find this requirement rather annoying in the majority of cases. = My functions and closures tend to be short and the number of local = variables I use =E2=80=94 both inside and outside the closure =E2=80=94ten= d to be small so I don't have a problem with confusing scope. Having to = explicitly name the variables in a use statement feels like unfortunate = overkill. But I do get your point. =20 OTOH, when inherited local variables are NOT modified within the = closure, does that actually cause a problem? (honest question) If not =E2=80=94 and please check my logic =E2=80=94 I would suggest PHP = 8.1+ could allow closures to IMPLICITLY inherit local variables, but = ONLY for variables that are READ, not for variables that are written. Given this approach, variables would still need to be declared when = variables need to be written, e.g. "use ( &$foo )" Although this relaxing of requirement to declare variables could = theoretically break existing code, only code where variables are read = inside closures before they are assigned with the same name as variables = assigned outside the closure would "break", and those cases are flagged = as a warning when error reporting is on. For me, that would probably cover 90%+ of the use cases my the = requirement to employ the "use" statement feels like overkill. -Mike