Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:126851 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by qa.php.net (Postfix) with ESMTPS id 4F0BC1A00BC for ; Wed, 19 Mar 2025 23:04:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1742425346; bh=bkF4f+D38mzBbsz/pBIO0CWLUNfF38z+nwkuNBAhlt8=; h=Date:Subject:To:References:From:In-Reply-To:From; b=cCdEzJlqMh0lD2Sqzc0u/2rgAr4OyPYJ/w4ztQ5smqkbiUmK6DAfrkAVgthnvDMOO i8I8uEEKuoKkRgOUvAsABqPzwukV13Q5oPID4U7ApdzY7bZznXcfhRDtOwolUqVMY+ ZcHoeOX7Nox3xvv8Tz+UJupfCVNe4hqNhWIgGckh93WqgFSphsV4a64nT3dzlE8Njf ElKeRx8+x08zQHM6RjTV18ewZX27tJXEkydwVySCPAzBEpVAkgE/zPaZVLxj6D9rJc kbn2ZaRKnIKQZB6TtRbg/1Sm5o6Ygto4bG8OdIGXtQBuHqsOtAlyG2feKOacL5Tznt NVvoEq38/6JtA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 802D4180083 for ; Wed, 19 Mar 2025 23:02:24 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-2.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_MISSING,HTML_MESSAGE, RCVD_IN_DNSWL_LOW,SPF_HELO_PASS,SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from fout-a6-smtp.messagingengine.com (fout-a6-smtp.messagingengine.com [103.168.172.149]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Wed, 19 Mar 2025 23:02:24 +0000 (UTC) Received: from phl-compute-01.internal (phl-compute-01.phl.internal [10.202.2.41]) by mailfout.phl.internal (Postfix) with ESMTP id 91CA713833F6 for ; Wed, 19 Mar 2025 19:04:54 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-01.internal (MEProxy); Wed, 19 Mar 2025 19:04:54 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rwec.co.uk; h=cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm1; t=1742425494; x=1742511894; bh=hb0K86XKhy PdOXO3UTTfHLcqTsGCmW9RM9BA3PWGb2o=; b=DsKoNbnD3NlNs4X2gsWhwMLtWA +1vzU/z067wyEKdcqasGlhqdvGWtX8X/iumge54pqm+aGYaSzn90y0Bd52w9BOSC sLdwMik0RZX69ixfTc5tIvRWhSt6KIAJwHUlTtcybuW2iZTU6YbU/WOi6WrVE3Fe H62E1Kvqkf7nvRmtb71pogez7mxKvC+wFxEe0d6zoQyHJ6rNAvQrdkLo+OUAAhs9 a6lxykdnvAGN+r/aLDIoEmSsm6jUTKeY3wO9TwEzNMJDlxO9JbPiRiQsH8s2j1R/ ND9x7MlOG5gInGw9uCkO7VamDMrC1jjumxv4Uz0s6LdXcjWwspiYrbNPpHwA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1742425494; x=1742511894; bh=hb0K86XKhyPdOXO3UTTfHLcqTsGCmW9RM9B A3PWGb2o=; b=f5AKA3idjz8pVBo4E+p3XkP3YXP/9y9NsBbTKyyFvckH/sYhvl1 246T4UQaT8YIor6/aWJrL/Dcqg9jLDe8+nOoi7R9Qk2W33dQccgqq5uklVcLPYi9 3Ur8bx5+bPKNI8NHcS9MwS6/qKrax+aM1t2uX0xO+QGQVbY1SV2ZNPwSvwAliJRn TQHYPBEGPMnBhkcJAXhsEDYt2jI7TyPTTHoRLjgc/rVEkiCUd0EYMfSAWTXzHgcu E2Ze5LZThnaO8KEQqRZjVYbV1r0hg3Qghj0QkBSAHm0QJu8PWjWZKaSV7Tncavth cWG90lF9zOoy1IzS2vxFte8Dy4rvA34cZbg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgddugeeiiedtucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggv pdfurfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucenucfjughrpegtkf ffgggfuffvfhfhjgesrgdtreertddvjeenucfhrhhomhepfdftohifrghnucfvohhmmhhi nhhsucglkffoufhorfgnfdcuoehimhhsohhprdhphhhpsehrfigvtgdrtghordhukheqne cuggftrfgrthhtvghrnhepheetleeiiefgueduieeuieffvdevheduueefkeejuefgffef tdeitdegtedtleetnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilh hfrhhomhepihhmshhophdrphhhphesrhifvggtrdgtohdruhhkpdhnsggprhgtphhtthho pedupdhmohguvgepshhmthhpohhuthdprhgtphhtthhopehinhhtvghrnhgrlhhssehlih hsthhsrdhphhhprdhnvght X-ME-Proxy: Feedback-ID: id5114917:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA for ; Wed, 19 Mar 2025 19:04:53 -0400 (EDT) Content-Type: multipart/alternative; boundary="------------GKTKy7SPNIbyln0yeVqm1rkx" Message-ID: <743c84d4-28db-4f68-80e5-3cad2dac6e68@rwec.co.uk> Date: Wed, 19 Mar 2025 23:04:49 +0000 Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PHP-DEV] PHP True Async RFC - Stage 2 To: internals@lists.php.net References: <72bd5401-53a9-409f-ad45-687333401961@rwec.co.uk> <6987D912-CE46-4145-A8CE-732CA590A522@rwec.co.uk> <2F013672-9937-4AB1-BC46-86F3D342BE6B@rwec.co.uk> Content-Language: en-GB In-Reply-To: From: imsop.php@rwec.co.uk ("Rowan Tommins [IMSoP]") This is a multi-part message in MIME format. --------------GKTKy7SPNIbyln0yeVqm1rkx Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit On 19/03/2025 19:24, Edmond Dantes wrote: > > Yes, that would probably be a bad choice as well. Which is why I've > repeatedly suggested a different keyword, and AFAIK you still haven't > actually voiced an opinion on that. > > > Does this concern the syntax of `spawn block {}` or did I miss something? We're talking around in circles a lot here, I think, let's try to reset and list out a load of different options, as abstractly as possible. I'm going to use the word "keyword" in place of "spawn", just to separate *syntax* from *naming*; and where possible, I'm going to use the names from the current grammar, not any other placeholders. 1: keyword expr 2: keyword function_call 3: keyword expr_except_function_call 4: keyword inline_function 5: keyword_foo expr 6: keyword_bar function_call 7: keyword '{' inner_statement_list '}' #1 is the most flexible: you have some way of specifying a callable value, which you pass to the engine, maybe with some arguments (concrete example: "spawn $my_closure;") #2 is the most concise for the common case of using an existing function, because you don't need to make a callable / closure pointing to the function first (concrete example: "spawn my_function('my argument');") BUT these two rules conflict: any function_call is also an expr, so we can't say "if it's an expr, do this; if it's a function_call, do that", because both are true at once. The next four are compromises to work around that conflict: #3 is a version of #1 which doesn't conflict with #2 - introduce a new grammar rule which has all the things in expr, but not function_call. This is technically fine, but maybe confusing to the user, because "spawn $foo == spawn $foo()", but "spawn foo() != spawn foo()()", and "spawn $obj->foo != $obj->foo()". #4 is really the same principle, but restricted even further - the only expression allowed is the declaration of an inline function. 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 #5 and #6 are the "different keywords" options: they don't conflict with each other, and #1 could be used with #6, or #2 with #5. In concrete terms, you can have "spawn_func_call $foo() == spawn_closure $foo", or "spawn $foo() == spawn_closure $foo", or "spawn_func_call $foo() == spawn $foo". #7 is the odd one out: it hides the closure from the user completely. It could be combined with any of the others, but most likely with #2 > In PHP, code blocks are not all the same. > - `if` / `then` / `else` / `try` / `switch` **do not create a new > scope**. > - `function` **does create a new scope**. > > When a programmer writes: > ```php > $x = 5; > spawn {$x++}; > ``` > Will they easily understand that |$x++| is not modifying the same |$x| > as before? > No, they won’t. They will have to remember that |spawn {}| creates a > closure, just like |function| creates a closure with a separate scope. OK, thanks; I think this is the point that I was missing - I was thinking that the engine creating a closure was just an implementation detail, which could be made invisible to the user. But you're right, the way variable scope works would be completely unlike anything else in the language. That probably rules out #7 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? If the aim is "a concise way to wrap a few statements", we've already failed if the user's writing out "function" and a "use" clause. If the aim is "a readable way to use a closure", rule #2 is fine. Yes, it means some extra parentheses if you squeeze it all into one statement, but it's probably more readable to assign the closure to a temporary variable anyway: // Legal under rule #2, but ugly spawn (function() use($whatever) {     do_something($whatever); })(); // Requires rule #4, saves a few brackets spawn function() use($whatever) {     do_something($whatever); }; // Only needs rule #2, and perfectly readable $foo = function() use($whatever) {     do_something($whatever); } spawn $foo(); -- Rowan Tommins [IMSoP] --------------GKTKy7SPNIbyln0yeVqm1rkx Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 8bit
On 19/03/2025 19:24, Edmond Dantes wrote:
>  Yes, that would probably be a bad choice as well. Which is why I've repeatedly suggested a different keyword, and AFAIK you still haven't actually voiced an opinion on that.


Does this concern the syntax of `spawn block {}` or did I miss something? 


We're talking around in circles a lot here, I think, let's try to reset and list out a load of different options, as abstractly as possible.

I'm going to use the word "keyword" in place of "spawn", just to separate *syntax* from *naming*; and where possible, I'm going to use the names from the current grammar, not any other placeholders.


1: keyword expr
2: keyword function_call
3: keyword expr_except_function_call
4: keyword inline_function
5: keyword_foo expr
6: keyword_bar function_call
7: keyword '{' inner_statement_list '}'


#1 is the most flexible: you have some way of specifying a callable value, which you pass to the engine, maybe with some arguments (concrete example: "spawn $my_closure;")

#2 is the most concise for the common case of using an existing function, because you don't need to make a callable / closure pointing to the function first (concrete example: "spawn my_function('my argument');")

BUT these two rules conflict: any function_call is also an expr, so we can't say "if it's an expr, do this; if it's a function_call, do that", because both are true at once.


The next four are compromises to work around that conflict:

#3 is a version of #1 which doesn't conflict with #2 - introduce a new grammar rule which has all the things in expr, but not function_call. This is technically fine, but maybe confusing to the user, because "spawn $foo == spawn $foo()", but "spawn foo() != spawn foo()()", and "spawn $obj->foo != $obj->foo()".

#4 is really the same principle, but restricted even further - the only expression allowed is the declaration of an inline function. 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

#5 and #6 are the "different keywords" options: they don't conflict with each other, and #1 could be used with #6, or #2 with #5. In concrete terms, you can have "spawn_func_call $foo() == spawn_closure $foo", or "spawn $foo() == spawn_closure $foo", or "spawn_func_call $foo() == spawn $foo".


#7 is the odd one out: it hides the closure from the user completely. It could be combined with any of the others, but most likely with #2



In PHP, code blocks are not all the same.  
- `if` / `then` / `else` / `try` / `switch` **do not create a new scope**.  
- `function` **does create a new scope**.  

When a programmer writes:  
```php
$x = 5;
spawn {$x++};
```
Will they easily understand that $x++ is not modifying the same $x as before?
No, they won’t. They will have to remember that spawn {} creates a closure, just like function creates a closure with a separate scope.


OK, thanks; I think this is the point that I was missing - I was thinking that the engine creating a closure was just an implementation detail, which could be made invisible to the user. But you're right, the way variable scope works would be completely unlike anything else in the language. That probably rules out #7

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?

If the aim is "a concise way to wrap a few statements", we've already failed if the user's writing out "function" and a "use" clause.

If the aim is "a readable way to use a closure", rule #2 is fine.

Yes, it means some extra parentheses if you squeeze it all into one statement, but it's probably more readable to assign the closure to a temporary variable anyway:

// Legal under rule #2, but ugly
spawn (function() use($whatever) {
    do_something($whatever);
})();

// Requires rule #4, saves a few brackets
spawn function() use($whatever) {
    do_something($whatever);
};

// Only needs rule #2, and perfectly readable
$foo = function() use($whatever) {
    do_something($whatever);
}
spawn $foo();


-- 
Rowan Tommins
[IMSoP]
--------------GKTKy7SPNIbyln0yeVqm1rkx--