Oh don't even get me started on this but I agree sooooo much.
> No, more people should be using memory managed languages like Java and Golang.
Well, I use both Golang and Rust depending on the need. We can have both, it's not an either-or.
Are you talking about enums?
A sum type is an idea from type arithmetic. Suppose we have two types A and B, and we want to produce a new type from those, the most common provision in languages is to let you make a product type, it has all the values of A multiplied by all the values of B, this may be available to you as a named tuple, perhaps named a "struct" or "class" in your preferred language.
But what if instead we added these types instead of multiplying them? The new type has the values of A plus the values of B ? That's a sum type.
Suppose I have three types which resemble booleans: mood (it's either happy or sad), size (huge or tiny) and activity (either sleeping or eating)
A sum type of these three would allow me to make a "brief" of a cat as one of the six values, either as its mood, its size or its activity. The cat brief can be sad, or sleeping, or tiny, but it cannot be sleeping and sad [in this model] any more than a cat's size could be both huge and tiny. There are 2 + 2 + 2 = six values of the brief type.
In contrast a product type, maybe lets call that "state" of the cat consists of separate values of each of the three constituents, so the state of a cat might be (sad, tiny, sleeping) or (happy, huge, eating) or any other combination. There are 2 * 2 * 2 = eight values of this state type.
Just as an arithmetic is kinda crap if it only has multiply but not add, a type system is kinda crap if it can't make sum types. Where complicated hard-to-get-right hacks are used (e.g. C++ std::variant) these are often unsatisfying both ergonomically and in terms of delivered functionality, so hence the desire to have actual sum types in the language.
Crucially that's not necessarily what's going on in Rust and (assuming it lands) won't be the actual implementation of C++ std::optional<T&> specialisation.
Instead the language can decide from the value which type it has. This is where Rust's Guaranteed Niche Optimisation kicks in. If we've promised the compiler that type T's values don't occupy the space needed fully, the GNO promises that sum types consisting of T plus one other value are the same size as T was. There is no "tag field".
In practice, the compiler can provide optimisations beyond the Guarantee. For example the compiler can see that OwnedFd (a file descriptor) has a niche so Option<OwnedFd> is the same size as OwnedFd (ie the same size as a C integer, typically 4 bytes), but it can also see that char has a huge niche. Many of the 32 bits aren't needed to store a 21-bit Unicode scalar value, so (although the guarantee doesn't apply) a sum type of a char and six hundred other named possibilities is the same size as just the char was.
Ah, I see you mention this at the end, I think it's worth highlighting much earlier, that the "tag" isn't actually a mechanically necessary part of such a type.