Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:128393 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 lists.php.net (Postfix) with ESMTPS id 6CCE91A00BC for ; Tue, 5 Aug 2025 06:39:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1754375870; bh=R0NW31uNIIK29ef+PLYt8lKqjYE2LltF4xGu7hKcZe8=; h=Date:From:To:Cc:In-Reply-To:References:Subject:From; b=N5iZdpK9qppkWTjxsEGRWGPshluCIFNKuUt3PKeTxBQBlmAqooSgphtdNbE69MZIa mQHsgVwT+cA8lktz7g0SBj1Oip8Jj7ao6eHAngnrAhQ2yxhLUuFC06cGez1nyoNH8P xthBBevuwuEhwptcicTauGU6lD5TJ43cqLh4+zacJHeOSlGbOCSS+0mtvarjibRSvV dHe7QsjugO1WOAkZToQSWEW1K/Npwrm8q27qwRmqLPpEGXFN6YWBuM7gw0PC6kt3Ts y94P89n/ZmpC6NU3t68/qmZY7oXf7J7JX3BMifJhLzHRgHgfUWVjWaxTfs5jyGlw3z Nvp9h2Zl8C3TA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 2C4F518003F for ; Tue, 5 Aug 2025 06:37:50 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) 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.1 X-Spam-Virus: No X-Envelope-From: Received: from fhigh-a6-smtp.messagingengine.com (fhigh-a6-smtp.messagingengine.com [103.168.172.157]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Tue, 5 Aug 2025 06:37:49 +0000 (UTC) Received: from phl-compute-05.internal (phl-compute-05.phl.internal [10.202.2.45]) by mailfhigh.phl.internal (Postfix) with ESMTP id A6A9F140020D; Tue, 5 Aug 2025 02:39:29 -0400 (EDT) Received: from phl-imap-05 ([10.202.2.95]) by phl-compute-05.internal (MEProxy); Tue, 05 Aug 2025 02:39:29 -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=fm1; t=1754375969; x= 1754462369; bh=okEzYLsMVnV3cJQx6Yc1OKhUoAqqrEXhZR9V3uki5kU=; b=F KXRhx6FVIZvJ/s+965jeoYiKABSA4SBs7gwfXBDk4E3eHG4xeEL5sG/V1zrnLJlc 4cfFCOxqVyRlBIo7YuOFnGbqDdhBiGRm92yGSTmClAsecr/psulScHwUMo/e8OqH x+L4enSQpcLfW/PRwelS1qjxMUNcOQyrH3Yn0Cp0OjFR2jMD0nqpVSVbkhlkCjFG AUYC81BaMSKLiFkvDaosBXGciYFj5IiB1ZCo3LcR85C/D45jVCGvbD2uAqd6o8jB zwyqtPCi6lnpa02l/800Zf4QxqKP/8DvsQWcMxW0mnQO0leYOLtVNwnCzyQpBMkj IKfDUqhNbRXS5UrVKe1vg== 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-sender:x-me-sender:x-sasl-enc; s=fm3; t= 1754375969; x=1754462369; bh=okEzYLsMVnV3cJQx6Yc1OKhUoAqqrEXhZR9 V3uki5kU=; b=Sm7IDApdqwsWj2/R4SqrzAk2ojRjRWY46Uo6Y9N9JO0I3buNfik 110Rr93pjrkcl1a/6X5a6QyLnhBw6Ke0QPSnSg+Nrg7PlflV0kxtrRyW6HdhaNin MNVlm+3F7ogK8bx+xfJKSdwhI2Wko65kMY8mxRbduFqbW03DZVuzTyla0w697y2D YRiXL+Mk8tLlmGFL9mZOiE1savdSIkQxAW4n2RlX6uYnPiMKgNYxu7ALKFRhY4dx eMjaa4bMc4SD0cYCp9PnRBLyKUcM7nWTSwh2paN4eybpidNwzZ+t4MTMz4xcyADz mf7X6nuC8NKWLX0y/jQLEJeU2iJHjOeDvfQ== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdefgdduudeggeejucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujf gurhepofggfffhvfevkfgjfhfutgesrgdtreerredtjeenucfhrhhomhepfdftohgsucfn rghnuggvrhhsfdcuoehrohgssegsohhtthhlvggurdgtohguvghsqeenucggtffrrghtth gvrhhnpeelkeefjeefteffvddvvdejgfduvdfggfeifedujeeijeetueeghfffveffhfdt jeenucffohhmrghinhepthhhvghphhhprdhfohhunhgurghtihhonhenucevlhhushhtvg hrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehrohgssegsohhtthhlvggu rdgtohguvghspdhnsggprhgtphhtthhopeefpdhmohguvgepshhmthhpohhuthdprhgtph htthhopehlrghrrhihsehgrghrfhhivghlughtvggthhdrtghomhdprhgtphhtthhopehi nhhtvghrnhgrlhhssehlihhsthhsrdhphhhprdhnvghtpdhrtghpthhtoheplhgvvhhimh esphhhphdrnhgvth X-ME-Proxy: Feedback-ID: ifab94697:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 2FCA61820074; Tue, 5 Aug 2025 02:39:29 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface Precedence: list list-help: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 X-ThreadId: AEartZH3PTBN Date: Tue, 05 Aug 2025 08:39:07 +0200 To: "Levi Morrison" , "Larry Garfield" Cc: "php internals" Message-ID: In-Reply-To: <9e43bf45-af3c-428e-8cf2-16772382d25b@app.fastmail.com> References: <9e43bf45-af3c-428e-8cf2-16772382d25b@app.fastmail.com> Subject: Re: [PHP-DEV] Blog post: If we can get partial generics, should we? Content-Type: multipart/alternative; boundary=50208afbc780482c997e9781c313517b From: rob@bottled.codes ("Rob Landers") --50208afbc780482c997e9781c313517b Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On Tue, Aug 5, 2025, at 08:19, Rob Landers wrote: >=20 > On Mon, Aug 4, 2025, at 22:49, Levi Morrison wrote: >> On Mon, Aug 4, 2025 at 9:26=E2=80=AFAM Larry Garfield wrote: >> > >> > Hi folks. I recently wrote a blog post on behalf of the PHP Founda= tion about some work Gina has been doing regarding generics. It's a fol= low-up to last year's post on a similar topic. We are especially lookin= g for feedback from the Internals crew, and voters in particular, on whe= ther or not to proceed. >> > >> > https://thephp.foundation/blog/2025/08/05/compile-generics/ >> > >> > Wearing my Internals/voter hat, my stance is a very strong "yes ple= ase!" >> > >> > -- >> > Larry Garfield >> > larry@garfieldtech.com >>=20 >> I played with a few iterations of Gina's work. My opinion at that time >> was that there are too many restrictions to be very useful. Based on >> those evaluations, I would not consider it to be "80% of the >> benefit.". With that said, maybe Gina has removed some of the >> restrictions. Based on the article it , but I'll commit to trying it >> out again. >>=20 >> One thing the article says we're missing and that we we definitely >> need is unions, or at the very least the union with null. Nullable >> types are everywhere, and even in your interfaces it's going to show >> up. For instance, if we had interfaces for Set, Map, etc, there are >> going to be operations which return nullable values. Sure, exceptions >> can be thrown in some cases but not all of them. For instance, if you >> are building a caching data structure, throwing an exceptions on a >> cache miss would be very bad for performance*. You can separate it >> into has + get, but this has two lookups which is not desirable for >> performance. You can return a "tuple" like `[found, $value]` where >> `$value` may be null, but this loses even more type safety, and isn't >> a very common pattern in PHP. You really want `T|null`. >>=20 >> There are probably other "edges" that are important and should be >> handled in this first pass, but missing nullable types is not a small >> thing. >>=20 >> * We'll get a mini-optimization in PHP 8.5 for making the exception >> object faster to construct, but it doesn't speed up the backtrace, >> which is where most of the performance cost comes from in practice. If >> you are benchmarking this, make sure to include cases where your stack >> is a few dozen frames deep. I work for an observability company for my >> day job, and it is insanely normal for there to be 10+ frames, and >> still fairly common to be 30+ frames. Think about routing, frameworks, >> middleware, helper functions, libraries and abstractions, etc. If you >> use middleware in particular, expect 50+ frames to be normal. >>=20 >=20 > I have a few different ideas for unions/intersections, but to implemen= t them now would be refactoring for the sake of refactoring. There would= be no benefit to implement any of it now. >=20 > Earlier this year I tried interning types, so that type checking could= be simple pointer equality. From there, I implemented a tri, such that = intersections and unions were very fast to check.=20 >=20 > The result is that it was virtually useless with today=E2=80=99s php, = except for the most pathological cases. PHP doesn=E2=80=99t do much type= checking =E2=80=94 currently. >=20 > In any case, the changes required to pull it off (not counting opcache= ) were huge. If we were to run into the pathological cases more often (s= uch as with runtime generics), it might be worth it. >=20 > All that being said, we are talking about *compile-time* generics. If = there is a time to be less efficient, it is during compilation, which ge= nerally happens once (esp with opcache). Further, pathological type chec= king is quite rare in codebases (most types are relatively simple withou= t deep hierarchical intersections and unions), so I assume it will be fi= ne to enable them. >=20 > =E2=80=94 Rob It=E2=80=99s also worth pointing out that nullable or a union of null an= d another type is technically just one type with the nullable bit set. S= o, I suspect nullable types will still obey the =E2=80=9Csingle type=E2=80= =9D rules proposed here.=20 =E2=80=94 Rob --50208afbc780482c997e9781c313517b Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable


On Tue, Aug 5, 2025, at 08:19, Rob Landers wrote:

On M= on, Aug 4, 2025, at 22:49, Levi Morrison wrote:
On Mon, Aug 4, 2025 at 9:26=E2=80=AF= AM Larry Garfield <larry@ga= rfieldtech.com> wrote:
>
> Hi folks.&nb= sp; I recently wrote a blog post on behalf of the PHP Foundation about s= ome work Gina has been doing regarding generics.  It's a follow-up = to last year's post on a similar topic.  We are especially looking = for feedback from the Internals crew, and voters in particular, on wheth= er or not to proceed.
>
>
> Wearing my Internals/voter hat, my stance is a very strong "yes p= lease!"
>
> --
>   Larr= y Garfield

I playe= d with a few iterations of Gina's work. My opinion at that time
was that there are too many restrictions to be very useful. Based on
those evaluations, I would not consider it to be "80% of the
benefit.". With that said, maybe Gina has removed some of the
restrictions. Based on the article it , but I'll commit to tryin= g it
out again.

One thing the article= says we're missing and that we we definitely
need is unions, = or at the very least the union with null. Nullable
types are e= verywhere, and even in your interfaces it's going to show
up. = For instance, if we had interfaces for Set, Map, etc, there are
going to be operations which return nullable values. Sure, exceptions<= /div>
can be thrown in some cases but not all of them. For instance,= if you
are building a caching data structure, throwing an exc= eptions on a
cache miss would be very bad for performance*. Yo= u can separate it
into has + get, but this has two lookups whi= ch is not desirable for
performance. You can return a "tuple" = like `[found, $value]` where
`$value` may be null, but this lo= ses even more type safety, and isn't
a very common pattern in = PHP. You really want `T|null`.

There are probab= ly other "edges" that are important and should be
handled in t= his first pass, but missing nullable types is not a small
thin= g.

* We'll get a mini-optimization in PHP 8.5 f= or making the exception
object faster to construct, but it doe= sn't speed up the backtrace,
which is where most of the perfor= mance cost comes from in practice. If
you are benchmarking thi= s, make sure to include cases where your stack
is a few dozen = frames deep. I work for an observability company for my
day jo= b, and it is insanely normal for there to be 10+ frames, and
s= till fairly common to be 30+ frames. Think about routing, frameworks,
middleware, helper functions, libraries and abstractions, etc. I= f you
use middleware in particular, expect 50+ frames to be no= rmal.


I have a few = different ideas for unions/intersections, but to implement them now woul= d be refactoring for the sake of refactoring. There would be no benefit = to implement any of it now.

Earlier this year I= tried interning types, so that type checking could be simple pointer eq= uality. From there, I implemented a tri, such that intersections and uni= ons were very fast to check. 

The result i= s that it was virtually useless with today=E2=80=99s php, except for the= most pathological cases. PHP doesn=E2=80=99t do much type checking =E2=80= =94 currently.

In any case, the changes require= d to pull it off (not counting opcache) were huge. If we were to run int= o the pathological cases more often (such as with runtime generics), it = might be worth it.

All that being said, we are = talking about compile-time generics. If there is a time to b= e less efficient, it is during compilation, which generally happens once= (esp with opcache). Further, pathological type checking is quite rare i= n codebases (most types are relatively simple without deep hierarchical = intersections and unions), so I assume it will be fine to enable them.

=E2=80=94 Rob

It=E2=80=99s also worth pointing out that nul= lable or a union of null and another type is technically just one type w= ith the nullable bit set. So, I suspect nullable types will still obey t= he =E2=80=9Csingle type=E2=80=9D rules proposed here. 
=E2=80=94 Rob
--50208afbc780482c997e9781c313517b--