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]