Hi Rob,

> This is a mischaracterization. To be more clear, the call itself approaches a 
> limit of 2x -- it isn't exactly 2x, and not all generic calls are always 2x. 
> I even gave real examples in my email showing real world generic heavy code 
> is only 30-50% slower. And this is without any real optimization work. This 
> is the ceiling, not a final result. Further, it appears to bear the same cost 
> as manually type checking the generics.

Real engineering, and the implementation is appreciated. But I
disagree that "approaches 2x worst case, 30-50% on real generic-heavy
code" reads as a small cost. Two reasons:

1. Generic-via-native isn't "use it OR keep using @template", once it
ships, the docblock alternative goes away.

Social pressure on every actively-maintained library is to migrate.
Static-analysis tools will gradually downgrade or drop (eventually)
their docblock-generic implementations once the native form is widely
available (this is exactly what happened with attributes vs PHPDoc
annotations after PHP 8.0). The cost isn't paid by libraries that opt
into runtime-reified generics; rather, it's paid by every library that
ships generics at all. Under either proposal, this is essentially
every typed library that exposes a collection, iterable, repository,
result type, or async primitive.

2. The cost compounds through the dependency graph, affecting even
users who don't write generics themselves.

Consider an application that never declares a generic of its own. It
depends on Psl. Psl is generic end-to-end, covering collections,
iterables, results, and options. Application code calling
`Psl\Vec\map($vec, $fn)` pays the reified-check cost on every call,
transitively, even though the application never wrote <...>.

Now a concrete tooling case:
[roave/BackwardCompatibilityCheck](https://github.com/Roave/BackwardCompatibilityCheck)
runs as a CI step. It uses its own generics. It depends on Psl. The
honest benchmark isn't "how much slower is one Psl\Vec\map call?",
it's "how much longer does BackwardCompatibilityCheck take to run on a
full codebase once Psl ships native generics and BCC adopts them?"If
the answer is 4 minutes -> 6 minutes per CI run, multiplied across
every PR in every project that uses BCC, that means slower CI, more
compute spend, and longer feedback loops for everyone downstream.

The "30-50% on generic-heavy code" framing also collapses once a user
can't tell which of their dependencies count as "generic-heavy." Under
this RFC, the cost question is "does your code use generics?", zero if
no, small if yes (the substituted-contract checks I just landed sit at
±0.1% benchmark noise). Under universal reification, the question
becomes "do you, or anything in your transitive dependency graph,
declare generic types?", and for an ecosystem where ORM repositories,
collection libraries, async runtimes, HTTP middleware kits, and
standard-library replacements all want generics, the honest answer is
"yes, everywhere."

This isn't an argument against reified generics in principle. It's an
argument that the perf characterisation in the post understates how
the cost will be felt in practice once the syntax is the way to do
generics in PHP. I think the right path is to land this RFC (erased +
substituted contract + reflection, zero cost for non-generic code,
small cost for substituted check sites), let the ecosystem migrate
from docblock to native, and then evaluate reified-via-opt-in on top
of it. Your branch is then the natural starting point for that
follow-up RFC, with much sharper data on what fraction of real PHP
workloads actually carry generic types in their hot path.

If that follow-up shows reified can land at a perf cost the ecosystem
can absorb across the dependency-graph case, great. If it can't, we'll
know, and the cost of finding that out will be much lower if the
erased form is the baseline rather than the starting point.

Cheers,
Seifeddine

Reply via email to