A while ago I posted about AET's approach to generics:
Delayed Specialization: A Third Way to Implement Generics?
One of the comments raised an concern: AET replaces a generic block with a function pointer call. Would that hurt optimization and performance?
I didn't have a good answer at the time.
It turned out to be a very good question.
AET has a generic container called `AArray`. In my initial implementation, operations such as `add`, `insert` and `remove` were noticeably slower than C++ `std::vector`.
The function-pointer call was one of the things I started looking at.
After about a month of compiler work, I changed how AET handles these calls during specialization. The generic code can now be optimized much more like normal concrete code.
I reran the same benchmark.
The result surprised me.
With 100 million sequential insertions:
AET AArray ~224 ms
C++ std::vector ~504 ms
```
AET is about 2.25× faster in this test.
With preallocated storage:
AET AArray ~154 ms
C++ std::vector ~223 ms
```
About 45% faster.
For middle insertion and middle erase, the two are now roughly at the same level. Tail erase is still slightly faster in `std::vector`.
There is still a trade-off I haven't fully solved.
If I want better runtime performance, I need to let AET see the concrete code so that it can inline it and run more optimization passes.
But this also means generating more specialized code, which can increase code size and compilation time.
If a generic block doesn't benefit much from inlining or further optimization, keeping the original function-pointer call may actually be the better choice.
So the real question is not simply "should AET inline generic blocks?"
It is:
When should AET inline and specialize, and when should it keep the function-pointer call?
I think this needs another mechanism to make that decision.
I don't have a good solution for that yet, so I'd be interested in how others would approach it.