Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:126854 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 2ED321A00BC for ; Thu, 20 Mar 2025 07:06:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1742454238; bh=3TsNAPxajHmuvDttuzogAdd6MlLMQI/NHcWwSKNKiaU=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=VFkFcaspXfT251TfNn4VjB5sOCHMG/cBR4DkBrMVL2bvMs6bvXZo2itarNhJL1eAe AWBgK+u2uDx7Ool0QOdHkQvayMLI9jMg7hnpul6SU2e9pSq1hPGOvyFXVSoY2KZGJ5 rA6eNaT+rot2suAoX/8NLAQ1ddBpQaHRlG4yIfHVCfL1qjU3yt5lObgj6dTL/18A68 3W4ZeF78oWjn97qd87DIP+15j2Evg67+tY5Uiq9sSU5ZJFyxmQCHjWGNfzsg9gr+RA QqnFNxymqlolGsubpCPFCYRnAPYEGxp7ZEJd2UDL/7fR7E3GMy/opniLh8uddALzdx oH4UQNNPQZwJw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 0679D180080 for ; Thu, 20 Mar 2025 07:03:57 +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=-3.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-yb1-f178.google.com (mail-yb1-f178.google.com [209.85.219.178]) (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 ; Thu, 20 Mar 2025 07:03:56 +0000 (UTC) Received: by mail-yb1-f178.google.com with SMTP id 3f1490d57ef6-e60aef2711fso276634276.2 for ; Thu, 20 Mar 2025 00:06:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1742454387; x=1743059187; darn=lists.php.net; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=KPnYz1PHS8xaBZ+ArBaNJEaQnmaptB5cQtUMkwh5Ixc=; b=DoTRf7wKs9/kl2YrM6sotH1OIAWS9o2S9mnR3u7+lMQuEuHKeD5t4zJ6O5CduCEpeW pfi7NKbf0DMRXbXDvUx+E3mc57+DhrlqfiDc6MRZFWFDhv9v7Dvrh1WbEqWQkYFUP0gO XAYmaC0I6Rl2wtDnFhdn4VGhqFBMomApsL4mEDY9LPrHNVHcoEnZdXp/f+pKFPfzCdTj bPJXk2JOD3Jmf0C2YrF6tE6Z8Llwb7TGpB28HQfbA/dkKRcjqgSHUtQvyL3W/3pDgMHK Bq7OW728CmmYFdw8c3TUH8YhWN9btRY5NSrH5vGrJjbNQEuMwtUgT3EzbViO0gbUmMfM m+rA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742454387; x=1743059187; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=KPnYz1PHS8xaBZ+ArBaNJEaQnmaptB5cQtUMkwh5Ixc=; b=Zw+RiNcMC9a2oxUUzxKJgKe2O0SqfygixgB1PmYYzv++ifvqSq99E+kPMuQjBcs4BP zBGHvfgkVkqCCWebl1Kjz0GMQV5gp2XaKpCTneq56mIeANQ4JKPa2zt0yMrjy0KW9X40 fZKhPujC6i1EEtCreaOuTbDFfsJs9D72RjhhftwDhCZAgFrxAqmO2O0YmxaRZopv58MW I4GNXpSJt1In11+tWSzo8oGRT7TOpU3mPcOs3EAobhaxOmWTYmEK3gSEiQ3/eTWgsoIs PmmdJO823dF8uiWStsDkdXps6c5MI0hwJHswv/AeFgRwebhimHWKHS2tT4bBvOAk+4vd Dnnw== X-Gm-Message-State: AOJu0Yx7mUulcKPBkPp4Hwrm/oak0k88rgdxeT5+KyGBZEksvK0mO9wD 2IuOqpl7rc6bJkgkf77dVhgHFch7wiilnOmIr5gJ2GoWleQd1ujiDKlLy7uSIWh30MHqLBgSFR+ vPcLR+QUzfMAEtnKAzeBQXe6YSlCL3qHOe3k= X-Gm-Gg: ASbGncvw8EmHtyb1gGJ8HBKMqho/Nl93jsKonR/yE46NOxnp4d6cYnUz9+0Dh/Bg33y /1HACkJTvFuCvKr3GNdsk3sex3BMbANL4XFvqv+3TnKbuSQHpQe/n1/em/ooaGTklxpSObeS/d9 wO4YZ9834Brv9MdON8nkpqkXDqvw== X-Google-Smtp-Source: AGHT+IGztxeUkZYNZ77XT5eQP3AdL4tKmcFkmPhgNU6NraLZQov+4cGIskdFgQl4bMhNdAdPbAxy5Xh1y8j41EB8pc8= X-Received: by 2002:a05:6902:11c4:b0:e64:6988:fdd2 with SMTP id 3f1490d57ef6-e6692021338mr2630814276.23.1742454386802; Thu, 20 Mar 2025 00:06:26 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 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> <743c84d4-28db-4f68-80e5-3cad2dac6e68@rwec.co.uk> In-Reply-To: <743c84d4-28db-4f68-80e5-3cad2dac6e68@rwec.co.uk> Date: Thu, 20 Mar 2025 09:06:16 +0200 X-Gm-Features: AQ5f1JoF3WKiLrH-UFoKdeTjVBvxrBBLx0_B6sKGCE5jSCJ-EqwHyiAyLsP6FJw Message-ID: Subject: Re: [PHP-DEV] PHP True Async RFC - Stage 2 To: "Rowan Tommins [IMSoP]" Cc: internals@lists.php.net Content-Type: multipart/alternative; boundary="000000000000c3461c0630c0c68a" From: edmond.ht@gmail.com (Edmond Dantes) --000000000000c3461c0630c0c68a Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable This is simply a wonderful explanation. I will be able to go through each point. But before that, let's recall what spawn essentially is. Spawn is an operation that creates a separate execution context and then calls a function within it. To perform this, spawn requires two things: 1. **callable** =E2=80=93 something that can be called; this is an expressi= on or the result of an expression. 2. **argument list** =E2=80=93 a list of arguments. > > 1: keyword expr > Then, this construct is a special case of another one: `keyword expr argument_list` However, PHP already has an expression that includes `expr argument_list`=E2=80=94this is `function_call`. Therefore, the `keyword function_call` variant is inherently a valid and complete form that covers all possible cases. So in the general case, `keyword expr` does not have a meaningful interpretation and does not necessarily need to be considered, especially if it leads to a contradiction. In other words: Option #1 is a special case. Option #2 is the general case. So, Option #2 should be our Option #1 because it describes everything. > > 3: keyword expr_except_function_call > If this expression is intended to call a closure, then essentially it is almost the same as #1. That means all our conclusions about #1 also apply to this option. > > 4: keyword inline_function > This option can be considered a special case of option #2. And that=E2=80= =99s exactly the case. > > 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 > A completely logical transformation that does not contradict anything. If I want to use a variable, this means: 1. I want to define a closure at point A. 2. I want to use it at point B. 3. Point A does not know where point B is. 4. Point B does not know what arguments A will have. 5. Therefore, I need to define a list of arguments to explicitly state what I want to do. The meaning of option #4 is different: 1. I want to define a closure at point A. 2. I want to use it at point A. 3. Point A knows what the closure looks like, so there is no need to define arguments =E2=80=94 it's the same place in the code. Therefore, the `keyword closure` does not break the clarity of the description, whereas the `keyword $something` does. > > 5: keyword_foo expr > The same #1. > > 6: keyword_bar function_call > This contains even more characters than the original and yet adds nothing useful. > > 7. 7: keyword '{' inner_statement_list '}' > let me add another nail to the coffin of this option: ```php class Some { public function someMethod() { spawn static function() { ... } } } ``` Another point in favor of option #4 is the `static` keyword, which is also part of the closure. > > 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? > Goal #1: Improve code readability. Make it easier to understand. Goal #2: Reduce the number of characters. The `spawn` keyword simplifies constructs by removing two parentheses and commas. For example: ```php spawn file_get_content("file"); vs spawn("file_get_content", "file"); ``` The first option looks as natural as possible, and spawn is perceived as a prefix. And that=E2=80=99s exactly what it is =E2=80=94 it essentially work= s like a prefix operation. In other words, its appearance reflects its behavior, assuming, of course, that we are used to reading from left to right. > > If the aim is "a concise way to wrap a few statements", we've already fai= led if the user's writing out "function" and a "use" clause. > Yes, but the `function ... use` syntax was not invented by us. We can't blame ourselves for something we didn't create. :) If closures in PHP were more concise, then `spawn + closure` would also look shorter. We cannot take responsibility for this part. > > If the aim is "a readable way to use a closure", rule #2 is fine. > Great. All that's left is to approve option #4 :) > > but it's probably more readable to assign the closure to a temporary variable anyway > In this case, we increase the verbosity of the code and force the programmer to create an unnecessary variable (not good). The advantage of option #4 is not just that it removes parentheses, but also that it keeps the code readable. It's the same as `(new Class(...))->method()` =E2=80=94 the point is not ab= out saving keystrokes (after all, nowadays ChatGPT writes the code anyway), but about the level of readability. It improves readability by about 1.5 times. That's the key achievement. The second reason why option #4 makes sense: it will be used frequently. And that means the programmer will often create unnecessary variables. Do you really want that? For example, `spawn fn() =3D> file_get_content()` won=E2=80=99t be, because= it doesn=E2=80=99t make sense. --000000000000c3461c0630c0c68a Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
This is simply a wonderful explanation. I= will be able to go through each point.

But before that, let's recall what spawn essenti= ally is. =C2=A0
Spawn is an operation that creates a separate execution = context and then calls a function within it. =C2=A0
To perform this, spa= wn requires two things:
1. **callable** =E2=80=93 something that = can be called; this is an expression or the result of an expression. =C2=A0=
2. **argument list** =E2=80=93 a list of arguments.=C2=A0=C2=A0

>
>=C2=A0 1: keyword expr
>

Then, this construct is a = special case of another one: =C2=A0
`keyword expr argument_list` =C2=A0<= br>
However, PHP already has an expression that includes `expr argument_= list`=E2=80=94this is `function_call`. =C2=A0
Therefore, the `keyword fu= nction_call` variant is inherently a valid and complete form that covers al= l possible cases.=C2=A0=C2=A0

So in the genera= l case, `keyword expr` does not have a meaningful interpretation and does n= ot necessarily need to be considered, especially if it leads to a contradic= tion.

In other words:
Option #1 is a special case.
Option #2 is the general case.
So, Option #2 should be our Option #1 because it describes everything.=C2= =A0=C2=A0

>
>=C2=A0 3: keyword expr_except_function_call
>
If this expression i= s intended to call a closure, then essentially it is almost the same as #1.=
That means all our conclusions about #1 also apply to this option.=C2=A0=C2= =A0

>
>=C2=A0 4: keyword inline_function
>
This option can be considered = a special case of option #2. And that=E2=80=99s exactly the case.=C2=A0

>
>=C2=A0 This is less confusing, but has on= e surprising effect: if you refactor the inline function to be a variable, = you have to replace it with "$foo()" not just "$foo", s= o that you hit rule #2
>

A completely logical transforma= tion that does not contradict anything. If I want to use a variable, this m= eans:

  1. I want to define a closure at point A.
  2. I want to use it at point B.
  3. Point A does not know where point B is.
  4. Point B does not know what arguments A will have.
  5. Therefore, I need to define a list of arguments to explicitly state wha= t I want to do.

The meaning of option #4 is different:

  1. I want to define a closure at point A.
  2. I want to use it at point A.
  3. Point A knows what the closure looks like, so there is no need to defin= e arguments =E2=80=94 it's the same place in the code.

Therefore, the `keyword closure`=C2=A0does not break the cl= arity of the description, whereas the `keyword $something` doe= s.

>
>=C2=A0 5: keyword_foo expr
>

The same #1.

>
>=C2=A0 6: keyword_bar function_call
>

This contains even more = characters than the original and yet adds nothing useful.
>
> 7.=C2=A0 7: keyword '{' inner_statement_list '}'
>
<= br>
let me add another nail to the coffin of this option:

= ```php
class Some {
=C2=A0 =C2=A0public function someMethod()
=C2= =A0 =C2=A0{
=C2=A0 =C2=A0 =C2=A0 =C2=A0spawn static function() {
=C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ...
=C2=A0 =C2=A0 =C2=A0 = =C2=A0}
=C2=A0 =C2=A0}
}
```

A= nother point in favor of option #4 is the `static` keyword, which is also p= art of the closure.

>
>=C2=A0 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?
>
Goal #1: I= mprove code readability. Make it easier to understand. =C2=A0
Goal #2: R= educe the number of characters. =C2=A0

The `spawn` keyword simplifie= s constructs by removing two parentheses and commas. For example: =C2=A0
```php
spawn file_get_content("file");
vs
spawn("file_get_content", "file");
```

The first option looks as natural as possib= le, and spawn is perceived as a prefix. And that=E2=80=99s exa= ctly what it is =E2=80=94 it essentially works like a prefix operation.=C2= =A0
In other words, its appearance reflects its behavior, assumin= g, of course, that we are used to reading from left to right.=C2=A0=C2=A0

>
>=C2=A0If the aim is "a concise way to wrap a few statem= ents", we've already=C2=A0failed if the user's writing out "function&qu= ot; and a "use" clause.
>

Yes, but the `f= unction ... use` syntax was not invented by us. We can't blame ourselve= s for something we didn't create. :) =C2=A0
If closures in PHP were = more concise, then `spawn + closure` would also look shorter. =C2=A0
We = cannot take responsibility for this part.

>=
>=C2=A0If the = aim is "a readable way to use a closure", rule #2 is fine.=
>
Great. All that's left is to approve option #4 :)=C2= =A0=C2=A0

>
>=C2=A0but it's probably more readable to assign the clos= ure to a=C2=A0= temporary variable anyway
>

In this case, we increa= se the verbosity of the code and force the programmer to create an unnecess= ary variable (not good). =C2=A0

The advantage of option #4 is not ju= st that it removes parentheses, but also that it keeps the code readable. = =C2=A0
It's the same as `(new Class(...))->method()` =E2=80=94 th= e point is not about saving keystrokes (after all, nowadays ChatGPT writes = the code anyway), but about the level of readability. It improves readabili= ty by about 1.5 times. =C2=A0
That's the key achievement.=C2=A0=C2= =A0

The second reason why option #4 makes sens= e: it will be used frequently.=C2=A0
And that means the programme= r will often create unnecessary variables. =C2=A0
Do you really want tha= t?=C2=A0

For example, `spawn fn() =3D> file_get_content()` won=E2= =80=99t be, because it doesn=E2=80=99t make sense.=C2=A0
--000000000000c3461c0630c0c68a--