Hi Nuno,
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.
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()=>expr, and a couple of earlier attempts
with different syntax and features).
Secondly, I'd like to point out that "short closures" actually have
three fundamental features:
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".
I think it's worth making clear which of those three features we are
hoping to retain by combining arrow functions with blocks.
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 = 'Hello World; echo $x; } cannot be
converted to { $x = 'Hello World; return echo $x; }. Alternatives
include converting to { $x = 'Hello World; echo $x; return null; } or
requiring all closure blocks to end with a valid expression.
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.
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.)
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.
If you want to capture variables $a, $b, and $c, but have local
variables $x, $y, and $z, you would currently write this:
$f = function() use ($a, $b, $c) {
// $x, $y, $z must be local, because not imported
}
If we added an opt-in syntax for "capture everything", we might instead
write this:
$f = function() use (*) {
$x = $y = $z = null;
}
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.
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.
In the above example I deliberately did not use the "fn()=>" 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.
I would personally prefer the "fn()=>" 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.
Regards,
--
Rowan Tommins (né Collins)
[IMSoP]
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php