Re: PHP True Async RFC - Stage 2

From: Date: Mon, 17 Mar 2025 07:58:22 +0000
Subject: Re: PHP True Async RFC - Stage 2
References: 1 2  Groups: php.internals 
Request: Send a blank email to [email protected] to get a copy of this message
Hello.

In this email, I will focus only on the syntax because it is a separate and
rather complex topic.

First, the RFC does not clearly describe the syntax, which needs to be
fixed.
Second, you are right that methods and operators cause confusion.
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.

## 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.

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.

## Spawn Operator

Yes, the chosen syntax has some ambiguity because there are two versions.
However, I didn't like the other options, mainly due to their verbosity.

**General syntax:**

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

where:

- parameters - a list of parameters passed to the closure.
- returnType - the return type of the closure.
- codeBlock - the body of the closure.

Examples:

```php
spawn function {
    echo "Hello";
};

spawn function:string|bool {
    return file_get_contents('file.txt');
};

// Incorrect syntax
spawn {
    echo "Test\n";
};
```

##### In scope expression

The in keyword allows specifying the scope in which the coroutine.

```php
$scope = new Async\Scope();

$coroutine = spawn in $scope function:string {
    return "Hello, World!";
};

function test(): string {
    return "Hello, World!";
}

spawn in $scope test();
```

The scope expression can be:
- A variable

```php
spawn in $scope function:void {
    echo "Hello, World!";
};
```

- The result of a method or function call

```php
spawn in $this->scope $this->method();
spawn in $this->getScope() $this->method();
```

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.

As for the form:

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

It makes the code unreadable, and carries no meaningful advantage.
Saving a single variable only to get lost in parentheses? It's not worth it.. :)

### Spawn Form


The form spawn <callable>(<parameters>);
is a shorthand for:

```php
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.

As for the form:

```php
spawn (<expression>)(parameters);
```

I suggest not implementing it at all.
It is simply terrible, makes the code unreadable, and carries no
meaningful advantage.
Saving a single variable only to get lost in parentheses? It's not worth it.. :)


### Why do I use the function keyword in the second form?

Only to allow defining the return type.

In principle, both forms are equivalent:

```php
spawn {};
spawn function {};
```

I also like the function keyword because it unambiguously indicates
that this is not just a block of code but specifically a closure.

What I don’t like:
This form might complicate semantic analysis since now there are two
types of closures to parse.
Intuitively, it would be good to define it like this:

```php
spawn function() use() {};
```

— meaning to literally mirror the standard closure definition.
This way, an existing analysis block could be reused.

But what should we do with parameters? :)

In other words, I would prefer this aspect to be reviewed by someone
who is equally well-versed in the implementation.

---

Ed.


Thread (59 messages)

« previous php.internals (#126800) next »