6 ms·
I'm surprised that it has any impact on performance at all, and I'd love to see the codegen differences between the applications. Mostly the `final` keyword se
by andrewla 3y ago
I'm surprised that it has any impact on performance at all, and I'd love to see the codegen differences between the applications.
Mostly the `final` keyword serves as a compile-time assertion. The compiler (sometimes linker) is perfectly capable of seeing that a class has no derived classes, but what `final` assures is that if you attempt to derive from such a class, you will raise a compile-time error.
This is similar to how `inline` works in practice -- rather than providing a useful hint to the compiler (though the compiler is free to treat it that way) it provides an assertion that if you do non-inlinable operations (e.g. non-tail recursion) then the compiler can flag that.
All of this is to say that `final` can speed up runtimes -- but it does so by forcing you to organize your code such that the guarantees apply. By using `final` classes, in places where dynamic dispatch can be reduced to static dispatch, you force the developer to not introduce patterns that would prevent static dispatch.
- deleted 3y ago[deleted]
- bgirard 3y ago> The compiler (sometimes linker) is perfectly capable of seeing that a class has no derived classes How? The compiler doesn't see the full program. The linker I'm less sure about. If the class isn't guaranteed to be fully private wouldn't an optimizing linker have to be conservative in case you inject a derived class?
- GuB-42 3y ago"inline" is confusing in C++, as it is not really about inlining. Its purpose is to allow multiple definitions of the same function. It is useful when you have a function defined in a header file, because if included in several source files, it will be present in multiple object files, and without "inline" the linker will complain of multiple definitions. It is also an optimization hint, but AFAIK, modern compiler ignore it.
- wredue 3y agoI believe the wording I’ve seen is that compilers may not respect the inline keyword, not that it is ignored.
- fweimer 3y agoGCC does not ignore inline for inlining purposes: Need a way to make inlining heuristics ignore whether a function is inline https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93008 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93008 (Bug saw a few updates recently, that's how I remembered.) As a workaround, if you need the linkage aspect of the inline keyword, you currently have to write fake templates instead. Not great.
- lqr 3y ago10 years ago it was already folklore that compilers ignore the "inline" keyword when optimizing, but that was false for clang/llvm: https://stackoverflow.com/questions/27042935/are-the-inline-keyword-and-inlining-optimization-separate-concepts/27044943#27044943 https://stackoverflow.com/questions/27042935/are-the-inline-...
- CuriousCosmic 3y agoThe thing with `inline` as an optimisation is that it's not about optimising by inlining directly. It's a promise about how you intend to use the function. It's not just "you can have multiple definitions of the same function" but rather a promise that the function doesn't need to be address/pointer equivalent between translation units. This is arguably more important than inlining directly because it means the compiler can fully deduce how the function may be used without any LTO or other cross translation unit optimisation techniques. Of course you could still technically expose a pointer to the function outside a TU but doing so would be obvious to the compiler and it can fall back to generating a strictly conformant version of the function. Otherwise however it can potentially deduce that some branches in said function are unreachable and eliminate them or otherwise specialise the code for the specific use cases in that TU. So it potentially opens up alternative optimisations even if there's still a function call and it's not inlined directly.
- ack_complete 3y ago> "inline" is confusing in C++, as it is not really about inlining. Its purpose is to allow multiple definitions of the same function. No, its purpose was and is still to specify a preference for inlining. The C++ standard itself says this: > The inline specifier indicates to the implementation that inline substitution of the function body at the point of call is to be preferred to the usual function call mechanism. https://eel.is/c++draft/dcl.inline https://eel.is/c++draft/dcl.inline
- lelanthran 3y ago> It is useful when you have a function defined in a header file, because if included in several source files, it will be present in multiple object files, and without "inline" the linker will complain of multiple definitions. Traditionally you'd use `static` for that use case, wouldn't you? After all, `inline` can be ignored, `static` can't.
- pjmlp 3y agoNo, because that would make it internal to each object file, while what you want is for all object files to see the same memory location.
- lelanthran 3y ago> No, because that would make it internal to each object file, while what you want is for all object files to see the same memory location. I can see exactly one use for an effect like that: static variables within the function. Are there any other uses?
- pjmlp 3y agoGlobal variables and the magic of a build system based on C semantics.
- wheybags 3y agoWhat if I dlopen a shared object that contains a derived class, then instantiate it. You cannot statically verify that I won't. Or you could swap out a normally linked shared object for one that creates a subclass. Etc etc. This kind of stuff is why I think shared object boundaries should be limited to the lowest common denominator (basically c abi). Dynamic linking high level languages was a mistake. The only winning move is not to play.
- lanza 3y ago> Mostly the `final` keyword serves as a compile-time assertion. The compiler (sometimes linker) is perfectly capable of seeing that a class has no derived classes That's incorrect. The optimizer has to assume everything escapes the current optimization unit unless explicitly told otherwise. It needs explicit guarantees about the visibility to figure out the extent of the derivations allowed.
- sixthDot 3y ago> I'd love to see the codegen differences between the applications There are two applications, dynamic calls and dynamic casts. Dynamic casts to final classes dont require to check the whole inheritance chain. Recently done this in styx [0]. The gain may appear marginal, e.g 3 or 4 dereferences saved but in programs based on OOP you can easily have *Billions* of dynamic casts saved. [0]: https://gitlab.com/styx-lang/styx/-/commit/62c48e004d5485d4fce8e6a327ea0b67ba134b6c https://gitlab.com/styx-lang/styx/-/commit/62c48e004d5485d4f....