On Tue, Aug 5, 2025, at 08:19, Rob Landers wrote:
> 
> On Mon, Aug 4, 2025, at 22:49, Levi Morrison wrote:
>> On Mon, Aug 4, 2025 at 9:26 AM Larry Garfield <la...@garfieldtech.com> wrote:
>> >
>> > Hi folks.  I recently wrote a blog post on behalf of the PHP Foundation 
>> > about some 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 whether 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 please!"
>> >
>> > --
>> >   Larry Garfield
>> >   la...@garfieldtech.com
>> 
>> 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.
>> 
>> 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`.
>> 
>> 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.
>> 
>> * 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.
>> 
> 
> I have a few different ideas for unions/intersections, but to implement them 
> now would 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 equality. From there, I implemented a tri, such that 
> intersections and unions were very fast to check. 
> 
> The result is that it was virtually useless with today’s php, except for the 
> most pathological cases. PHP doesn’t do much type checking — currently.
> 
> 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 (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 be less efficient, it is during compilation, which generally 
> happens once (esp with opcache). Further, pathological type checking is quite 
> rare in codebases (most types are relatively simple without deep hierarchical 
> intersections and unions), so I assume it will be fine to enable them.
> 
> — Rob

It’s also worth pointing out that nullable or a union of null and another type 
is technically just one type with the nullable bit set. So, I suspect nullable 
types will still obey the “single type” rules proposed here. 

— Rob

Reply via email to