Re: PHP True Async RFC - Stage 2

From: Date: Thu, 20 Mar 2025 08:11:37 +0000
Subject: Re: PHP True Async RFC - Stage 2
References: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  Groups: php.internals 
Request: Send a blank email to [email protected] to get a copy of this message


On 20 March 2025 07:06:16 GMT, Edmond Dantes <[email protected]> wrote:


I forgot to include some relevant text to quote, but I absolutely agree that syntax #2 should be our
default. 

I think the only thing I'm still unsure of is whether we need anything else on top of it, and
if so what.


>
>>  4: keyword inline_function
>>
>This option can be considered a special case of option #2. And that’s
>exactly the case.


In terms of the grammar, it is a special case of #1, because the inline_function is evaluated in
full as an expression, and then we *fabricate* a zero-argument function call to the resulting value.

Or to use your breakdown, #2 includes both elements we need: the callable, and the parameter list;
#1, #3 and #4 all include just one element, the callable, and make the assumption that the argument
list is empty. 



>>  This is less confusing, but has one surprising effect: if you refactor
>>the inline function to be a variable, you have to replace it with "$foo()"
>>not just "$foo", so that you hit rule #2
>
>A completely logical transformation that does not contradict anything.


This example maybe helps explain why this might be surprising:

```
function foo() {
    yield  function() { whatever(); };
    spawn  function() { whatever(); };
    return function() { whatever(); };
}
```

Three identical values, so let's replace with a shared variable:

```
function foo() {
    $action = function() { whatever(); }
    yield $action;
    spawn $action;
    return $action; 
}
```

Looks right, but isn't - we needed to write "spawn $action()". Not a huge rule to
learn, but a fairly arbitrary one from the point of view of the user.



>The meaning of option #4 is different:
>
>   1. I want to define a closure at point A.
>   2. I want to use it at point A.
>   3. Point A knows what the closure looks like, so there is no need to
>   define arguments — it's the same place in the code.



This feels like a stretch to me: it's not that anything knows what arguments to pass, it's
just that the syntax is restricted to passing no arguments. (You could presumably define a closure
that *expects* arguments, but couldn't actually pass any, within the shorthand syntax.)



>Therefore, the keyword closure does not break the clarity of the
>description, whereas the keyword $something does.


From the user's point of view, it might be just as obvious that the closure put into a variable
two lines above can also be called with zero arguments. It's only as unclear as any other code
involving a variable - if it's badly named and defined 100 lines away, you'll have a
problem, but no syntax can solve that.



>>  6: keyword_bar function_call
>>
>This contains even more characters than the original and yet adds nothing
>useful.


I tried to make clear that the keywords could stand in for anything. There's no reason that
"two different keywords" has to mean "more characters". It could be "go
foo();" and "run $closure;", and the point I was trying to illustrate would still
hold.



>>  But I do want to come back to the question I asked in my last e-mail:
>what is the use case we're trying to cater for?
>>
>Goal #1: Improve code readability. Make it easier to understand.
>Goal #2: Reduce the number of characters.


That's answering a different question, I want to know *what code* we are optimizing the
readability of. What is the user trying to do, which we want to make readable and shorter?

Specifically, what is the use case where syntax #2, "spawn function_call" is not good
enough, leading us to add a special case into the grammar.


>The advantage of option #4 is not just that it removes parentheses, but
>also that it keeps the code readable.


One is a consequence of the other. I don't disagree, but I personally find that introducing a
temporary variable has much the same effect, without any special case grammar.



>The second reason why option #4 makes sense: it will be used frequently.


Will it? By who, when? Honest question, and comes back to my point about identifying the use case.


>For example, spawn fn() => file_get_content() won’t be, because it
>doesn’t make sense.


If return values end up somewhere, I  don't think it would be hard to come up with examples
that were slightly more than one function call, but still fit in a single-expression closure.


Rowan Tommins
[IMSoP]


Thread (59 messages)