points by vlovich123 5 years ago

Beyond the ergonomics, `std::variant` is horribly outperformed by basic type erasure mechanisms or inheritance. Every time I've tried to use `std::variant` I've been unhappy with the runtime performance vs any other way to solve this problem (the compile time performance is expectedly atrocious compared to any other method).

So you've got poor ergonomics, poor compilation performance, bloated code size, and poor runtime performance. I've written an enormous amount of C++ code from applications to libraries to system development. I literally have never found a place where `std::variant` has any positives that can't be written a different, clearer way with drastically better compile time and run time performance.

jcelerier 5 years ago

> Beyond the ergonomics, `std::variant` is horribly outperformed by basic type erasure mechanisms or inheritance.

uh, I have yet to see variants beaten by inheritance in practice - in particular as soon as you have type erasure all your containers have an additional level of indirection (which can be solved partially by Boost.PolyCollection but that adds its own layer of complexity) and that has been a much bigger perf-killer - with variants memory is nicely packed when iterating over your array of values and that's by far the biggest performance thing you can do. You also need to allocate memory dynamically everywhere which is a no-go in a lot of cases.

  • vlovich123 5 years ago

    Like I said, I was shocked but I was building something recently and, like you, reached for std::variant first to make the solution more generic while, in theory, outperforming type erasure/inheritance. Thankfully I had thorough micro benchmarks and was able to demonstrate convincingly that type erasure was drastically faster in practice, despite the theory (and virtual inheritance was better than both)..

    I think what ends up happening is that std::variant and how you access it is pretty code bloaty and hasn’t been optimized yet properly by library authors and compilers. It’s also not particularly ergonomic so even though it’s been around for 3 years there’s not really any incentive (it’s slow and unergonomic, slow adoption, not the highest area for focusing on improving ergonomics and performance).

    I think type erasure is overly criticized on how bad it performs. A single indirection in a hot loop is actually extremely CPU friendly as it’s predictor will keep the pipeline filled and you’ll be unlikely to end up flushing the pipe. It’s something the CPU has been optimized for since polymorphism is present in one way or another in all paradigms. Equally I suspect vtable costs are denigrated for no good reason. Like the cost is there (and you can accidentally overuse it) but the vtable is information to the compiler (+ it wouldn’t surprise me if CPUs had special tricks to make c++ vtables even faster) that can result in faster perf than you could achieve any other way. Again. I’m not talking about the theory here. I’m talking about the actual performance I wrote thorough microbenchmarks on.

    The amount of code that gets generated to do discriminated std::variant unions is absurd which I suspect is a large part of the problem. I’m impressed that the standards body managed to pull off being so bad on so many dimensions. I’m not saying it’s a bad library. It has very specific requirements it’s trying to maintain specific to how the STL is written. Abseil’s HashTable reimplementation (SwissTable) should show how many of the invariants the STL likes to enforce in practice aren’t invariants anyone cares about and inhibit good performance.

    Said another way. std::variant is probably the most efficient discriminated union you could get past the standards body to be included in the STL. Rust’s performs way better on any metric and that should give you a glimpse that the incentives in the standards body are misaligned with what’s actually needed to keep C++ healthy. I think - I haven’t benchmarked but tagged unions are so embedded in the language and type system rather than as “dumb” library code I can’t imagine they have the inefficiency baggage of std::variant.

jpcooper 5 years ago

I don’t have a huge amount of experience writing C++ code. What are these other more efficient ways? I suppose virtual classes is one, but it becomes difficult to add functions.