On 17/03/2025 07:58, Edmond Dantes wrote:

However, I really liked the `$scope->spawn()` construct in the example code, as it feels the most natural compared to `spawn in`. Moreover, the `spawn in` expression is quite complex to implement, but I don't have enough experience to evaluate it properly.


I agree, it's a natural way of making the spawn happen "on" the scope; but it potentially makes spawning in a scope a "second-class citizen" if `spawn foo($bar);` has to be expanded out to as `$scope->spawn( fn() => foo($bar) );` just to add a scope.

There are other ways it could be included, like with some extra punctuation:

spawn($scope) foo($bar);
spawn<$scope> foo($bar);
spawn@$scope foo($bar);


## Defer

I have nothing against the `suspend` keyword.
However, the `defer` keyword raises some questions. "Defer" means to postpone something (to delay execution). But in this case, it’s not about "postponing" but rather "executing upon function block exit." I don't know why the creators of Go chose this word. I considered `finally`, but it is already used in the `try` block.


I did say the names were subject to bikeshedding; my main point was that this was one of the actions that should have a keyword. I mostly chose "defer" because it's what used in other languages, and "onexit" sounds like "run at end of program".

That said, "defer" makes perfect sense to me: the action is not run immediately, it's delayed (deferred) until the end of the scope.

do_this_first();
defer do_this_later();
do_this_second();


The implementation also concerns me a bit.
It seems that to fully implement the `defer` block, we would need something similar to `finally`, or essentially make `defer` create an implicit `try...finally` block.


I'm confused - $scope->onExit() is already in the RFC, and I wasn't suggesting any change other than the syntax. (Although I'm not sure if it should defer to coroutine exit rather than scope exit by default?)




**General syntax:**

```php
spawn [in <scope>] function [use(<parameters>)][: <returnType>] {
<codeBlock>
};
```

The "function" keyword just looks out of place here, because there's never a function the user can see. I also don't like that it's almost-but-not-quite a valid closure expression - the missing () looks like a typo.

If the syntax is going to be that close, why not just allow an actual callable? That way, a user can write an anonymous function with all the features already supported - return types, captured variables (you've labelled them "parameters" here, but that's not what a "use" statement lists), etc.


In an earlier draft of my e-mail, I was going to suggest a "spawn call" variant, where:

spawn foo(42);
// spawns a call to foo with argument 42

spawn call $callable;
// spawns a call to whatever's in $callable, with no arguments

spawn call function() use($foo, &$bar) { do_whatever($foo, $bar); };
// creates a Closure, and spawns a call to it

spawn call bar(...);
// mostly equivalent to "spawn bar();", but with some extra overhead

spawn call create_me_a_lovely_function('some', 'args');
// calls the function directly, then asserts that the result is a callable, and spawns a call to that with no arguments


Or maybe they're just two different keywords:

async_run foo(42);

async_call $callable;

In general, I prefer code to be explicit and unambiguous at a glance, rather than concise but ambiguous unless you've memorised the grammar. So if there are two forms of "spawn", I'd prefer to spell them differently.


The form `spawn <callable>(<parameters>);`
is a shorthand for `spawn use(<callable>, <parameters>) { return ... };`
The expression `<callable>(<parameters>);` is not executed directly at the point where `spawn` is used but in a different context.

There is a slight logical ambiguity in this form, but it does not seem to cause any issues with comprehension.


Is this just a description of your own comprehension, or based on some more general experience of something similar?


As for the form:

`spawn (<expression>)(parameters)` — I suggest not implementing it at all.


I'm not sure what you mean by <callable> above. Slightly expanding out the actual parser rules from php-src, a function_call can be:

name argument_list
class_name T_PAAMAYIM_NEKUDOTAYIM member_name argument_list
variable_class_name T_PAAMAYIM_NEKUDOTAYIM member_name argument_list
callable_variable argument_list
dereferenceable_scalar argument_list
new_dereferenceable argument_list
'(' expr ')' argument_list

Where callable_variable is a slightly misleading name, and includes expanding recursively to function_call, as in the add(1)(2) form beloved of Function Programmers


Is there a reason to redefine all of this and make fresh decisions about what to allow?

I would argue for "principle of least surprise": reuse or emulate as much of the existing grammar as possible, even if you personally would never use it.


--
Rowan Tommins
[IMSoP]

Reply via email to