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 internals+get-126858@lists.php.net to get a copy of this message
On 20 March 2025 07:06:16 GMT, Edmond Dantes <edmond.ht@gmail.com> 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]

« previous php.internals (#126858) next »