On Friday, May 15th, 2026 at 7:13 AM, Nicolas Grekas
<[email protected]> wrote:
> I'd like to put a syntax proposal on the table that may address Rowan's
> concern, and that also addresses something I'm worried about independently:
> the migration path for existing libraries.
> How does a library that uses @template docblocks today migrate to native
> syntax without forcing a BC break on its consumers? Multiplied across the
> libraries out there, this is a major point of tension for the ecosystem we
> need to anticipate.
> Existing @template annotations were adoptable gradually *because* they're
> invisible to the engine.
> Native <T> syntax, as the RFC proposes it, doesn't have that property: a
> library cannot adopt it without bumping its minimum PHP version and pulling
> all its consumers with it.
> We've solved this exact problem once before for attributes. The #[...] syntax
> was deliberately designed so older PHP versions would parse it as a # line
> comment, which is what made the adoption across the ecosystem so smooth.
> The same trick is available for generics if we pick the right delimiter.
> Concretely, write #<...> everywhere <...> appears in the current RFC:
> declarations, inheritance clauses, type uses in signatures, call-site
> arguments. One syntax, used uniformly.
> Three benefits, beyond the migration story:
>
> 1. FC for free. A library can adopt native generics in source today and
> continue running on older PHP versions, because the engine just sees
> comments. No need to coordinate with the min-PHP bump.
> 2. The turbofish goes away. No need to disambiguate < from less-than
> comparison. With #<...>, the token is unique and unambiguous everywhere: at
> declaration, use, and call site. We get to drop a whole grammar mechanism
> rather than introduce one.
> 3. Rowan's concern is addressed typographically. Anything inside #<...> is
> the erased, SA-enforced layer; everything outside follows the engine's normal
> runtime-checked rules.
>
> For codebases that want to adopt native generics while still supporting
> earlier PHP versions, #<...> would need to sit at the end of a line so older
> parsers consume it as a # line comment. Code targeting only generics-aware
> PHP can write it inline. The line-break constraint is a transitional
> code-style cost, not a permanent property of the syntax, and it's bounded by
> however long libraries support pre-generics versions.
> WDYT? I expect Seifeddine has good reasons to prefer the current syntax. I'd
> like to put this on the table because the FC story it unlocks, combined with
> the turbofish simplification, might be worth the trade-off and might help
> gather a broader consensus.
> Cheers,
> Nicolas
>
How would generic types be expressed in parameters and return types?
```php
// Current RFC:
function DoStuff<T>(myParam: T, otherParam: int): T {
// ...
}
```
Existing PHP versions will have no clue what `T` is. Only one of the uses of
`T` here is inside `<...>`. Wrapping the others in `#<...>` would be
syntactically incoherent (and rather ugly, I think). But the only alternative
that comes to mind is:
```php
function DoStuff#<T>(myParam#: T, otherParam: int)#: T {}
// which would have to look like this in projects continuing to support prior
PHP versions:
function DoStuff#<T>
(
myParam#: T
, otherParam: int // bizarre comma placement
)#: T
{
// ...
}
```
Syntax parsing would, I suspect, be rather more complicated, unless you
required the type to be placed in parentheses, which would only make the syntax
even less appealing:
```php
function DoStuff#<T>(myParam#:(T), otherParam: int)#:(T) {}
// and in projects continuing to support prior PHP versions:
function DoStuff#<T>
(
myParam#:(T)
, otherParam: int
)#:(T)
{
// ...
}
```
If not for those (major, in my view) syntactical issues, I might've been on
board with the idea. (Just to be clear, I don't have voting privileges.)
Conceptually, it feels proper to use "#" again for structured metadata that has
*some* engine-enforced functionality, but which is primarily targeted at
(static analysis) developer tools. But once one realizes that generics will be
used in places outside of `<...>`, I think the viability of the syntax
crumbles, and I'd rather just have the original proposal.