4 ms·
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 e
by valenterry 4y ago
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.
- insanitybit 4y agoUnions 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.
- valenterry 4y agoWell, 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.
- insanitybit 4y agoI must not be understanding what you're asking for because it sounds like anonymous sum types.
- valenterry 4y agoMaybe this is just about terminology. 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.
- wtetzner 4y agoThe problem is that if you have e.g. let x: u64|i32 = ... It's impossible for the compiler to do anything with x without adding some kind of runtime type tag. The representations of those types are different. But with something like OCaml's polymorphic variants, you could do e.g. let x: Big(u64)|Small(i32) = ... and then switch on the tag (Big or Small) to determine what to do with the values.
- valenterry 4y ago> It's impossible for the compiler to do anything with x without adding some kind of runtime type tag. Yes, in this particular case that's true. If the developer tries to do anything except maybe printing it for debug then the compiler will tell the developer so and the developer will have to switch to sumtypes / wrap it just like it is done in OCaml by default.
- dllthomas 4y agoIIUC this kind of union would discriminate only on type.
- proto_lambda 4y agoHow 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.
- valenterry 4y agoYou 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.
- proto_lambda 4y ago> You can obviously only call common methods 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.
- valenterry 4y agoIt 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.