CSE doesn’t work across function boundaries unless those functions are inlined, which won’t happen with virtual functions due to the above.
What compiler are you using that devirtualizes every class hierarchy? I suspect that Casey is using C++ so he may (unfortunately) have multiple translation units in his program.
Yes, the video uses C++.
Obviously if one compiles a library then the compiler has no way of knowing that other subclasses of `shape_base` do not exist. My point is that when compiling a binary as they are doing for their video, the compiler knows that there are no other subclasses that it needs to cater to.
It might require LTO explicitly, of course. At the very least godbolt doesn't devirtualize without LTO [1], but godbolt itself breaks if I enable LTO [2] and I CBA to test locally right now.
The fundamental problem here is that C++ doesn't have a good abstraction to represent visibility of public types, since any other translation unit - even across the DLL boundary! - can re-declare the type and then derive from it. The only way to constrain visibility is to use anonymous namespaces, and that only works if the type can be confined to a single unit (that C++ compilers seem to ignore the optimization opportunities here in practice perhaps indicates just how rare this actually is).
Refactorings are moves you can make. Choosing when to make them is up to you. In fact, Fowler provides guidance along with each refactoring suggesting when it might be applicable (i.e., not always)
For one: Most compilers for most languages are bad by that metric, and interpreters don't even get to play. So this is not helpful for the vast majority of people. Waiting around for them becoming good is not a viable option.
Second, say the compiler would perform good in this scenario. Cool, lets go up a notch, or two, and it would start performing bad again, because there are limits to what it can do in a reasonable amount of time.
And if that limit were big that maybe wouldn't matter, but the limit is low, and so it does. Real programs are so much more complex than this example, that even if the compiler got 10 times better, it would still fail to optimize large parts of your real program.
re: the speedup from moving from subclassing to enums - Compiler isn't pulling its weight if it can't devirtualize in such a simple program.
re: the speedup from replacing the enum switch with a lookup table and common subexpression - Compiler isn't pulling its weight if it can't notice common subexpressions.
So both the premise and the results seem unconvincing to me.