On 15 May 2026 17:11:22 BST, Larry Garfield <[email protected]> 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]

Reply via email to