On 18 March 2025 08:22:18 GMT, Edmond Dantes <edmond.ht@gmail.com> wrote:
spawning in a scope a "second-class citizen" if `spawn foo($bar);`
Reminds me of *"post-purchase rationalization"* or the *"IKEA effect".*
when effort has already been invested into something, and then suddenly,
there's a more convenient way. And that convenient way seems to devalue the
first one.
That's not really what I meant. I meant that if you're learning the language, and see feature A has native and intuitive syntax, but related feature B is a method call with an awkward signature, you will think that feature A is more "normal" or "default", and feature B is "specialist" or "advanced".
If we want to encourage people to think that "spawn in current scope" is the default, to be used 99% of the time, I guess that's fine. But if we want using scopes to feel like a "natural" part of the language, they should be included in the "normal" syntax.
And if we have short forms for both on day one, I don't see any need to also have the long forms, if they end up needing slightly different semantics around closures and parameters.
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?)
Yes, that's correct. The onExit method can be used for both a coroutine and
a Scope.
As for the method name onExit, it seems like it would be better to replace
it with something clearer.
I'm still confused why you started talking about how to implement "defer". Are you saying that "onExit" and "defer" are different things? Or that giving it dedicated syntax changes the implementation in some fundamental way?
spawn call bar(...);
It doesn't make sense because the arguments must be defined.
As with any other callable, it would be called with no arguments. It was just an illustration, because the function_name(...) syntax is one of many ways of creating a callable in PHP.
Is there a reason to redefine all of this and make fresh decisions about
what to allow?
If we strictly follow syntax consistency, then of course, we need to cover
all possible use cases.But when I see code like this:
spawn ($this->getSome()->getFunction())($parameter1, ...);
I start seeing circles before my eyes.
Sure, any flexible syntax lets you write subjectively horrible things.
But like with allowing object keys and adding Async\Key objects, this isn't the place to redesign existing language features based on personal taste.
If the feature is "you can put a function call here", let's not waste time writing a new definition of "function call" - the scope of this project is already big enough already!
A great example of exactly this is the First-Class Callables RFC: PHP: rfc:first_class_callable_syntax
> The syntax CallableExpr(...) is used to create a Closure object that refers to CallableExpr with the same semantics as Closure::fromCallable().
> CallableExpr can be any expression that can be directly called in the PHP grammar.
That's pretty much the whole definition, because the implementation directly uses the existing function_call grammar rule. The only caveat is that calls using the nullsafe ?-> operator are forbidden - for reasons directly related to the feature, not because Nikita thought they were ugly.
spawn <exp> [with (<args>)];
...
spawn test with ("string");
spawn test(...) with ("string");
Only the second of these meets the proposed rule - `test(...)` is an expression which evaluates to a Closure object; `test` as an expression refers to a constant, which I'm pretty sure is not what you intended.
If you allowed any callables, not just Closures, this would technically be valid:
spawn "test" with ("string");
But most likely you'd still want a separate syntax for a direct function call, however you want to spell it:
spawn_this_closure_ive_created_somehow function() {
do_something();
do_something_else();
};
spawn_this_closure_ive_created_somehow test(...) with ("string");
spawn_this_function_call_without_creating_a_closure test("string");
Or forget callables, and anything that looks like it's trying to be one, because creating a Closure isn't actually the user's aim:
spawn_this_function_call_without_creating_a_closure test("string");
spawn_these_statements_use_a_closure_if_you_like_i_dont_care {
do_something();
do_something_else();
}
--
Rowan Tommins
[IMSoP]