Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:125068 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 E41FB1A00BD for ; Tue, 20 Aug 2024 12:42:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1724157873; bh=yiiv4ZHZKWkd7O+KEE1KMecROmcqUIWhaEfk177v8kA=; h=Date:From:To:Cc:In-Reply-To:References:Subject:From; b=VoR3tAcY71yK0yFjPZkPBX7l7Ycc14FBhwpkMm6B6PPohkWCjXquhv2e4k9J+R63j 1D/M3VQEzZ1Hx3qHOlZC+Tw9DP759YAl7sJr/1j4bIPL0rkS9GixJpWr6GTERHyGjF ZGU19qX8z0CuFbyDn/EG5dDfsohmEgNnn00lFMPQ2uvTsln8IQ1Vb0jgd0NGxT4UXI eUv+1RjtvnrMB4gOEFuOVyxCWqCKG9yXupcwJYg16BQxcIMrc20srlS/iNNIr1Gh4D je7NPPYvCZwDK1gaOCipkZjv4FXx2vioJRUcBlKZ9ScF64fxbStL8JyFQYCKDvzwn7 nT65dwG7jtdMA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id CC2C2180068 for ; Tue, 20 Aug 2024 12:44:31 +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=-0.1 required=5.0 tests=BAYES_50,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 fout4-smtp.messagingengine.com (fout4-smtp.messagingengine.com [103.168.172.147]) (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 ; Tue, 20 Aug 2024 12:44:31 +0000 (UTC) Received: from phl-compute-02.internal (phl-compute-02.nyi.internal [10.202.2.42]) by mailfout.nyi.internal (Postfix) with ESMTP id 07DA3138FC31; Tue, 20 Aug 2024 08:42:41 -0400 (EDT) Received: from phl-imap-09 ([10.202.2.99]) by phl-compute-02.internal (MEProxy); Tue, 20 Aug 2024 08:42:41 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bottled.codes; h=cc: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=fm2; t=1724157761; x= 1724244161; bh=yiiv4ZHZKWkd7O+KEE1KMecROmcqUIWhaEfk177v8kA=; b=p gjHrtofKMco0eVT927O6VyqWMeeJZXtuay/ujZW7p6EwUFvrq9R11he+ep7+S6YB /B9CuY29FBV0XXKcuUH5Xfd8OhTMy4uln+o+hFNCMGoxw2uhnF3SdFuBycmWov7U C8GtyqHF50jOQG5ni1X51odYQtuXCW5XOX1rzT/SQ7HAk+ULLxaE1G2tTx8hp7C9 30eO6OtDBug1jiEssW064M1NAGvkd8M+itlprRylPMxrM5pZ0tK/E5SGa/Aco139 YbEc2MeKwONhJly/fK+Lbud/G2HusVmSxHvokWhrA0B2fiuDx5sMq4npC1L0mVK+ dR0rAReaB71/aUrXSaz+w== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc: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-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; t=1724157761; x=1724244161; bh=yiiv4ZHZKWkd7O+KEE1KMecROmcq UIWhaEfk177v8kA=; b=En2aW+AmhItZBzMdoWvjD1FG2RtDeyeTTBf5c1bWQ9fr YpMI1dZXrubxxeI/V5w7weP4unb9e7C6+ug3mzADwU1frGNXQKQ0epfovgdxYRzV W/8MCUX15q+ATLqbNjxxYSU6aJw8WHKBajCq+rnBTH8422s+h1/Hq53X/PGY6zZg cS5Zd0HpKtISqkjpNvKFuMVTzcvX3XGJ6uLsPxCkI8D451G09+9I7MWS/Qmez3+j 0knyKGfdLYfUBqUYCzfaKDmlElar0k04DZZyk8QEd9Ni4t1nfn6w2hpDF1lF3yqF eeNkNmB9KIe7idwccLGc0Io0917SsXso62fjbDVgXw== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeftddrudduiedgheegucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggvpdfu rfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucenucfjughrpefoggffhf fvvefkjghfufgtsegrtderreertdejnecuhfhrohhmpedftfhosgcunfgrnhguvghrshdf uceorhhosgessghothhtlhgvugdrtghouggvsheqnecuggftrfgrthhtvghrnhepieeute ehvddvfeejhffgieehleehhedthfefkeejffelgfevvdekudetjeejtddtnecuvehluhhs thgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomheprhhosgessghothhtlh gvugdrtghouggvshdpnhgspghrtghpthhtohepvddpmhhouggvpehsmhhtphhouhhtpdhr tghpthhtoheprghrnhgruhgurdhlsgesghhmrghilhdrtghomhdprhgtphhtthhopehinh htvghrnhgrlhhssehlihhsthhsrdhphhhprdhnvght X-ME-Proxy: Feedback-ID: ifab94697:Fastmail Received: by mailuser.nyi.internal (Postfix, from userid 501) id A1DFA15A005E; Tue, 20 Aug 2024 08:42:40 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 Date: Tue, 20 Aug 2024 14:42:19 +0200 To: "Arnaud Le Blanc" Cc: internals@lists.php.net Message-ID: In-Reply-To: References: <1b59392a-68cb-36eb-0fef-977ac7113520@php.net> Subject: Re: [PHP-DEV] State of Generics and Collections Content-Type: multipart/alternative; boundary=f9a4dcb2c5094dc1a7d6cc518f873b81 From: rob@bottled.codes ("Rob Landers") --f9a4dcb2c5094dc1a7d6cc518f873b81 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On Tue, Aug 20, 2024, at 14:08, Arnaud Le Blanc wrote: > Hi Rob, >=20 > On Mon, Aug 19, 2024 at 7:51=E2=80=AFPM Rob Landers wrote: >=20 > > > Invariance would make arrays very difficult to adopt, as a library= can not start type hinting generic arrays without breaking user code, a= nd users can not pass generic arrays to libraries until they start using= generic arrays type declarations. > > > > This seems like a strawman argument, to a degree. In other words, it= seems like you could combine static arrays and fluid arrays to accompli= sh what you are seeking to do. In other words, use static arrays but all= ow casting to treat it as "fluid." > > > > In other words, simply cast to get your example to compile: > > > > function f(array $a) {} > > function g(array $a) {} > > > > $a =3D (array) [1]; // array unless cast > > > > f($a); // ok > > g((array)$a); // ok > > > > And the other way: > > > > function f(array $a) {} > > function g(array $a) {} > > > > $a =3D [1]; > > > > f((array)$a); // ok, type check done during cast > > g($a); // ok >=20 > There is potential for breaking changes in both of your examples: >=20 > If f() is a library function that used to be declared as `f(array > $a)`, then changing its declaration to `f(array $a)` is a > breaking change in the Static Arrays flavour, as it would break > library users until they change their code to add casts. I don't think we should be scared of breaking changes; php 9.0 is coming= =F0=9F=94=9C anyway. You could also consider it as "an array might be a= rray, but an array is always an array" >=20 > Similarly, the following code would break (when calling g()) if h() > was changed to return an array: >=20 > function h(): array {} > function g(array $a); >=20 > $a =3D h(); > g($a); >=20 > Casting would allow users to pass generic arrays to libraries that > don't support generics yet, but that's expensive as it requires a > copy. Why does it require a copy? It should only require a copy if the content= s are changed (CoW) and at that point, you can know what rules to apply = based on the coerced/casted type. I'm doing a similar thing for the Lite= ral Strings RFC, where it is a type that is also indistinguishable from = a string until something happens to it and it is no longer a literal str= ing. So passing a array to a function that only accepts an array shouldn= 't matter. Once inside that function, all type-checking can be disabled = for that array. One approach to that could be to just smack a "type-chec= k strategy" function pointer on zvals, potentially, as that would give t= he most flexibility for casting, aliases, generics, etc. Don't get me st= arted on the current type checking; it is a mess and inconsistent depend= ing on what is doing the checking (constructor promoted props, propertie= s, method args, function args). Then you can just copy the zval, change = a function pointer, but point it to the same array (which will CoW) and = change the strategy during casting. In other words, you could cheaply cast an array to array by= (essentially) changing a couple of function pointers, but array= to array would be expensive. So I imagine there would strategies f= or changing strategies... probably. I don't know, I literally just thoug= ht of this off the top of my head, so it probably needs more work. >=20 > Best Regards, > Arnaud >=20 =E2=80=94 Rob --f9a4dcb2c5094dc1a7d6cc518f873b81 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable

=
On Tue, Aug 20, 2024, at 14:08, Arnaud Le Blanc wrote:
Hi Rob,

On Mon, Aug 19, 2024 at 7:51=E2=80=AFPM Rob Land= ers <rob@bottled.codes> w= rote:

> > Invariance would make array= s very difficult to adopt, as a library can not start type hinting gener= ic arrays without breaking user code, and users can not pass generic arr= ays to libraries until they start using generic arrays type declarations= .
>
> This seems like a strawman argum= ent, to a degree. In other words, it seems like you could combine static= arrays and fluid arrays to accomplish what you are seeking to do. In ot= her words, use static arrays but allow casting to treat it as "fluid."
>
> In other words, simply cast to get = your example to compile:
>
> function = f(array<int> $a) {}
> function g(array $a) {}
=
>
> $a =3D (array<int>) [1]; // arr= ay unless cast
>
> f($a); // ok
> g((array)$a); // ok
>
> A= nd the other way:
>
> function f(array= <int> $a) {}
> function g(array $a) {}
<= div>>
> $a =3D [1];
>
> f((array<int>)$a); // ok, type check done during cast
> g($a); // ok

There is potentia= l for breaking changes in both of your examples:

If f() is a library function that used to be declared as `f(array<= br>
$a)`, then changing its declaration to `f(array<int>= $a)` is a
breaking change in the Static Arrays flavour, a= s it would break
library users until they change their cod= e to add casts.

I don't think = we should be scared of breaking changes; php 9.0 is coming =F0=9F=94=9C = anyway. You could also consider it as "an array might be array<T>,= but an array<T> is always an array"


Similarly,= the following code would break (when calling g()) if h()
= was changed to return an array<int>:

= function h(): array {}
function g(array $a);

$a =3D h();
g($a);

Casting would allow users to pass generic arrays to libraries that=
don't support generics yet, but that's expensive as it re= quires a
copy.

W= hy does it require a copy? It should only require a copy if the contents= are changed (CoW) and at that point, you can know what rules to apply b= ased on the coerced/casted type. I'm doing a similar thing for the Liter= al Strings RFC, where it is a type that is also indistinguishable from a= string until something happens to it and it is no longer a literal stri= ng.

So passing a array<int> to a func= tion that only accepts an array shouldn't matter. Once inside that funct= ion, all type-checking can be disabled for that array. One approach to t= hat could be to just smack a "type-check strategy" function pointer on z= vals, potentially, as that would give the most flexibility for casting, = aliases, generics, etc. Don't get me started on the current type checkin= g; it is a mess and inconsistent depending on what is doing the checking= (constructor promoted props, properties, method args, function args). T= hen you can just copy the zval, change a function pointer, but point it = to the same array (which will CoW) and change the strategy during castin= g.

In other words, you could cheaply cast a= n array<int> to array<string> by (essentially) changing a co= uple of function pointers, but array<string> to array<int> w= ould be expensive. So I imagine there would strategies for changing stra= tegies... probably. I don't know, I literally just thought of this off t= he top of my head, so it probably needs more work.


Be= st Regards,
Arnaud



=E2=80=94 Rob
--f9a4dcb2c5094dc1a7d6cc518f873b81--