Not sum types. Those are union types. The difference is important, since if you work with two results (or two functions that return results) that use the same error-type you most often don't want to end up with a tuple of two times the same error but simply A<String, Error>.
Of course, if you care about which error is from which function, you can always easily do that by wrapping them into a sumtype, but in practice this is a rather rare use-case in application code at least.
How would that work in a memory safe language? Rust does have (named) untagged unions already (using the `union` keyword), but they are unsafe to use because there is no way to know statically which of the possible variants a given value contains.
You can obviously only call common methods or have to pattern match later and have a way to tell them apart. If you can't tell them apart, the compiler will tell you and you need to tag them somehow.
That sounds like trait objects/dynamic dispatch/`dyn`, which comes with runtime costs.
> or have to pattern match later and have a way to tell them apart.
That "way to tell them apart" is a tag, which would make it a tagged union/enum, not an untagged union. Those already exist, though not in an anonymous flavour.
It does, but the developer decides. Also, errors are often propagated and only matched in exceptional cases, so I don't think the impact would be big.
> That "way to tell them apart" is a tag, which would make it a tagged union/enum, not an untagged union.
No. The difference is that a tagged union (sum type) is defined in advance but generally a union is not necessarily tagged but _can_ be tagged.
Example: say you have tagged union with 3 different types / tags A, B and C.
You can now define an adhoc/untagged union that is A | C. That means, we can guarantee at compile time, that we will be able to tell A and C apart later. But it is still not the same, because the combination of A and C was decided adhoc and was not predefined by the developer anywhere necessarily - which is what makes it different from A, B, C which where specifically defined by the developer.
Unions don't have a discriminant. Anonymous Sum types have a discriminant, you just can't name it. Unions in Rust are unsafe because you can't tell what the underlying value will be.
Well, that depends. If the union consists of two types that share the same underlying structure, then obviously at runtime we can never know what the value is.
But otherwise we can. And this is something that we will know at compile-time, so we can prevent runtime-checks that would not work.
But essentially, when it comes to union types, they behave like sets. The compiler merges them. (A | B) | (A | B) is the same as A | B. But for sum types (even anonymous ones such as tuples) the compiler can't merge them because that would lose information (if the result is from the first A | B or the second one). Instead, you end up with a nested structure.
Which one is desired depends on the use-case, but it's definitely different.
Of course, if you care about which error is from which function, you can always easily do that by wrapping them into a sumtype, but in practice this is a rather rare use-case in application code at least.