On 13/06/2022 14:52, Larry Garfield wrote:
That's one perspective. The other perspective is that the proposal is to
extend closure syntax to support automatic capture.
As noted before, this is a distinction without a difference.


It's a difference in focus which is very evident in some of the comments on this thread. For instance, Arnaud assumed that adding "use(*)" would require a change to arrow functions, whereas that never even occurred to me, because we're looking at the feature through a different lens.


By the way, the current RFC implies you could write this:

fn() use (&$myRef, $a) { $myRef = $a * $b; }
The RFC already covers that.  $b will be auto-captured by value from scope if it exists.  
See the "Explicit capture" section and its example.


So it does. I find that extremely confusing; I think it would be clearer to error for that case, changing the proposal to:

> Short Closures support explicit by-reference capture with the |use| keyword. Combining a short closure with explicit by-value capture produces an error.

And the example to:

$a = 1;
fn () use (&$b) {
    return $a + $b; // $a is auto-captured by value
                         // $b is explicitly captured by reference
}


Clearer syntax for this has been cited previously as an advantage of use(*) or use(...):

$a = 1;
function () use (&$b, ...) { // read as "use $b by reference, everything else by value"
    return $a + $b;
}


1. Auto-capture could still over-capture without people realizing it.  Whether 
this is actually an issue in practice (or would be) is hard to say with 
certainty; I'm not sure if it's possible to make an educated guess based on a 
top-1000 analysis, so we're all trying to predict the future.


I tried to make very explicit what I was and was not disputing:

> Whether the risk of these side effects is a big problem is up for debate, but it's wrong to suggest they don't exist.

The RFC seems to be implying that the implementation removes the side effects, but it does not, it is users paying attention to their code which will remove the side effects.


Arguably it's less of an issue only because short-closures are, well, short, so 
less likely to reuse variables unintentionally.


Our current short closures aren't just a single *statement*, they're a single *expression*, and that's a really significant difference, because it means to all intents and purposes *they have no local scope*. (You can create and use a local variable within one expression, but it requires the kind of twisted code that only happens in code golf.)

If there are no local variables, there is nothing to be accidentally captured. That's why the current implementation doesn't bother optimising which variables it captures - it's pretty safe to assume that *all* variables in the expression are either parameters or captured.


2. The syntactic indicator that "auto capture will happen".  The RFC says "fn".  You're 
recommending "use(*)".  However, changing the indicator syntax would do nothing to improve point 1.


The reason I think it would be better is because it is a more *intentional* syntax: the author of the code is more likely to think "I'm using an auto-capture closure, rather than an explicit-capture closure, what effect will that have?" and readers of the code are more likely to think "hm, this is using auto-capture, I wonder which variables are local, and which are captured?"

Of course they can still guess wrong, but I don't think "fn" vs "function" is a strong enough clue.


(Making fn and function synonyms sounds like it would have a lot more knock-on 
effects that feel very out of scope at present.)


Off the top of my head, I can't think of any, but I admit I haven't tried hacking it into the parser to see if anything explodes.


Regards,

--
Rowan Tommins
[IMSoP]

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to