Re: [RFC] [Discussion] Bound-Erased Generic Types

From: Date: Fri, 15 May 2026 17:10:29 +0000
Subject: Re: [RFC] [Discussion] Bound-Erased Generic Types
References: 1 2 3 4 5  Groups: php.internals 
Request: Send a blank email to internals+get-130898@lists.php.net to get a copy of this message
On 15 May 2026 17:11:22 BST, Larry Garfield <larry@garfieldtech.com> wrote: >> Straw man example: >> >> class Foo ~~Foo<T> extends Bar ~~Bar<int,T> { >> public function foo(string ~~non-empty-string $in): array ~~list<T> { >> ... >> >> >> Maybe PHP would process the syntax, but not the semantics, of the extra >> type information; SA tools would then be free to invent new pseudotypes >> within that framework, without needing to wait for a full PHP release >> cycle every time. > >This feels like it would be isomorphic to attributes, no? Syntax validated, available via >reflection, but nothing done with it. Yeah, the basic concept is "attributes on types", but with a more concise syntax. There are, I think, three basic cases such a syntax would need to handle: - the "SA type" is the "runtime type" qualified by a generic parameter, either placeholder or concrete: e.g. Collection vs Collection<T> or Collection<int>, array vs array<Foo> - more generally, the "SA type" is the "runtime type" with extra rules applied: e.g. string vs non-empty-string - the "SA type" is something that just can't be expressed at all, and the "runtime type" has to be "mixed" or some other broad type: e.g. "function foo(): T", where T is a type parameter on a generic class. For the first two, you can just suffix the extra information rather than repeating yourself, so more like this: class Foo~<T> extends Bar~<int,T> { public function foo(string~non-empty $in): array~<T> { Other than properties, annotating with "mixed" is redundant anyway, so you could have this public function bar(~T): ~T { But if you wanted to enforce the lower bound, you'd have to manually include it: public function bar(int~T): int~T { It's obviously not as elegant as making every type string reserved natively, but it allows for much faster iteration in SA tools, and could replace all their use of docblocks over night. As and when the language added full runtime support for those types, users could just delete the ~ (or whatever delimiter we used) and opt in to enforcement. "class Foo~<T>" would be an erased generic, "class Foo<T>" would be a reified or monomorphized one. Regards, Rowan Tommins [IMSoP]

« previous php.internals (#130898) next »