C++17 added std::variant and std::visit in its repertoire. They are worth a close examination. I've been wondering about whether they are always better than inheritance for modeling sum-types (fancy name for discriminated unions) and if not, under what circumstances they are not. We'll compare the two approaches in this blog post. So here it goes.
std::variant and std::visit idiom resembles closely to pattern matching in functional languages. However, functional languages are leaps and bounds ahead of the current capabilities of the pattern matching idiom.
Inheritance | std::variant |
---|---|
Need not know all the derived types upfront (open-world assumption) | Must know all the cases upfront (closed-world assumption) |
Dynamic Allocation (usually) | No dynamic allocation |
Intrusive (must inherit from the base class) | Non-intrusive (third-party classes can participate) |
Reference semantics (think how you copy a vector of pointers to base class?) | Value semantics (copying is trivial) |
Algorithm scattered into classes | Algorithm in one place |
Language supported (Clear errors if pure-virtual is not implemented) | Library supported (poor error messages) |
Creates a first-class abstraction | It’s just a container |
Keeps fluent interfaces | Disables fluent interfaces. Repeated std::visit |
Supports recursive types (Composite) | Must use recursive_wrapper and dynamic allocation. Not in the C++17 standard. |
Adding a new operation (generally) boils down to implementing a polymorphic method in all the classes | Adding a new operation simply requires writing a new free function |
Use the Visitor design pattern to get some of the benefits of the right hand side |
std::variant and std::visit idiom resembles closely to pattern matching in functional languages. However, functional languages are leaps and bounds ahead of the current capabilities of the pattern matching idiom.
- Generally, pattern matching makes it easy to dissect a variant type (or even a structured type) by the "shape" of the type and its content. I.e., a more powerful pattern matching in C++ would use structured bindings in some way.
- Conditional structured bindings would match only if the condition is satisfied.
- Matching on the dynamic type of the variable would be really nice but without paying excessive performance cost.
See a detailed example on slideshare.
Comments
You might find it useful if you work with variants/optionals a lot.