Hacker News new | ask | show | jobs
by jackling 767 days ago
Could you not get most of the benefits of ADTs using structs + unions + enums? I've used the pattern where I had a union of several types and an enum to differentiate which one to pick. Something like std::variant seems to work a bit like a sum type.

The only issue is you can't do a clean switch statement that matches on the specific value of a field, but nested switch statements aren't that messy.

4 comments

Yes, and you can also get many of the benefits of OOP with convention and discipline, but doing so requires you to frequently get down in the weeds since, e.g., vtables must be dealt with manually.

The trouble with this approach is that there's a lot of mental overhead in dotting all of your i's and crossing all of your t's. It's draining, so you start to, e.g., shoehorn additional functionality into existing classes instead of making new ones.

You eventually wind up perceiving the abstraction as costly which lessons your use of it at the expense of producing a more elegant solution to the problem(s) you're solving.

tl,dr? The ability to just state "Darmok and Jalad at Tanagra" is transformative when the alternative is telling an entire story every time you want to reference a complex idea.

> Could you not get most of the benefits of ADTs using structs + unions + enums?

The modelling aspects can be simulated, yes, but that's barely half of the benefits of ADTs. Pattern matching is a big ergonomic benefit.

TFA gets pattern matching.

The critical thing is that the compiler (or macro system) needs to check that you've checked all the alternatives.

Yes TFA is pretty close, but note that it's not just "structs + unions + enums" getting you "most of the benefits", which is what I was responding to. There's a buttload of macros hiding allocation and switch statements.
The absolutely critical thing is to have checked every alternative when dealing with a sum type value. This is hard to do with macros, though not impossible (basically you'd need a macro to start a matching context and which introduces a variable in which to keep track of all the alternatives checked, then you need to arrange for the end of the matching context to check that all alternatives were checked).
I generally don't mind C++ for most code when it's absolutely necessary, but I'm not a huge fan of std::variant. Using std::visit to exhaustively match all cases feels hacky. It really would benefit from being a first-class language feature. It's more impactful to a lot of day-to-day code than other things they've worked on, such as coroutines.
The 4th example at https://en.cppreference.com/w/cpp/utility/variant/visit that uses a class template makes the feature a bit nicer, but still not as ergonomic as something like Rust.