Hacker News new | ask | show | jobs
by nicoburns 2050 days ago
Statically typed languages without Sum Types (aka tagged unions aka enums) which includes Java, C# and C++ amongst others drive me crazy: they have no ergonomic way to express "or" types. This is a massive expressive hole which (along with lacking type inference) I believe is responsible for a lot of the hate towards statically typed languages.
7 comments

This is one of the joys of TypeScript.

Some of my coworkers complain about being required to use TS instead of JS, and I just wonder why in the world you would want to use JS in a massive codebase.

It is, although the syntax for proper sum types (it calls them "discriminated unions") is really verbose in Typescript. I wish they'd make it more terse so people didn't use untagged sum types and hacks like `typeof` all the time.
Sealed classes in Kotlin largely solve that problem for me, and Java is getting those. It's not quite the same, but most of the time I find that if I'm trying to do Int|String, it's primitive obsession and there is actually a better sealed type hierarchy I'm missing.
If you care about the exact underlying memory layout such high-level types are way too blackbox-y. I doubt that historically this specific feature was responsible for any "static typing hate" (because languages with such high-level type systems were quite obscure 10 or 20 years ago). I have the impression that this hate was specifically a web-dev thing because many Javascript developers never experienced what it's like to work with a statically typed language until Dart and Typescript showed up (and then it suddenly was the best thing since sliced bread).
> Statically typed languages without Sum Types (aka tagged unions aka enums) which includes Java, C# and C++ amongst others drive me crazy: they have no ergonomic way to express "or" types. This is a massive expressive hole which (along with lacking type inference) I believe is responsible for a lot of the hate towards statically typed languages.

Union types coming in Scala 3

Yes, totally agree. It's the lack of statical type systems like this one that makes people hate them - for good reasons.
These languages have far better type systems than languages like python or javascript, that's not a reason to hate them.
We are talking about user experience here. In that regard, comparing python/javascript with Java/C++ is comparing apples with oranges.
We are talking about Python and JavaScript from the top of this comment chain, and the 'user experience' of writing Java/C# is closer to Python and JavaScript than to, say, Haskell.
Yes, but I find that the user experience of writing Rust or Swift is closer to that of JS than C# and Java.
Why? Rust's type system is basically a more sophisticated version of Java's, JS is in the opposite direction - a much simpler dynamic type system. Rust's lifetimes and borrow checker is additional complexity that JS doesn't have. Rust has longer compilation times than JS, longer than Java. Etc.
Modern versions of these languages have these features to a varying degree.
std::variant or std::any don't count? Overloading doesn't count? Templates don't count?

Seems like you should play with C++ a bit more.

Not a C++ developer, but from what I read, it says: "A variant is not permitted to hold references, arrays, or the type void". These are quite some limitations and don't really give a "smooth" experience.
None of those types make sense in variants. This is obvious to C++ programmers.

With all due respect, if you're not qualified to make assertions about something, perhaps refrain from labeling it as "quite the limitation".

Can you explain why it makes no sense for it to hold an array or void? I'm really curious and will take back my claim.
You cannot trivially compare or move an array. Note that `std::array` is still allowed in `std::variant` - just not C-style arrays.

As for references, you cannot re-bind references. Rationale here: https://stackoverflow.com/a/27037871/510036

As for void, apparently the reasons I had in my head are not the reasons in real life. I thought it might be because of a destructible requirement on the type, but it turns out there really isn't a good reason why they disallowed it, and that a future standard might allow it.

In any event, there are a multitude of variant implementations that allow all sorts of things depending on the behavior you want. Nothing is forcing you to use the standard library.

Thank you for the explanation!

I just wonder why it is hard to make a variant-type that works with everything. Well, if the language prevents e.g. reference rebinding, there can't be done much.

But not being able to put _anything_ into a variant severely limits the way it can be used for abstraction. Especially for library authors, because they might not no what their users will pass them. So when they write a generic method, that uses variants under the hood, they would have to "pass down" the restrictions to the user and tell them not to pass e.g. void. Same for the interaction of two libraries.

Or am I misunderstanding the constraints here?

std::variant is basically a parody of everything wrong with modern C++.
Please elaborate because I strongly disagree with you.