3 ms·
You're right, I'm not sure how I thought that it worked only with Result. Thanks for the correction. > Ceylon would be a closer case where nullable types are r
by Zababa 5y ago
You're right, I'm not sure how I thought that it worked only with Result. Thanks for the correction.
> Ceylon would be a closer case where nullable types are represented as sum types and not a special-case in the language (`String | Null` is the same as `String?`).
Aren't those union types? My understanding is that they are different from sum types, as you usually have to declare the sum types beforehand, and sum types are collections of values, while union types are collections of types, and are often declared "on the spot". At least that's how they work in Typescript, I don't know much about Ceylon.
To go back to option types, people usually like them because there are well-known patterns to program with them (like map). Of course you can get the same safety with static flow analysis (Typescript does this), but I think part of it is ergonomics, influenced by functional programming. Though if there is an overhead like in Java, I'm not sure about their value.
- brabel 5y agoI don't know if there's a meaningful difference between sum types and union types as both end up allowing a variable to be of one of a set of types. Ceylon: alias StringOrInt = String | Integer; StringOrInt myValue = "foo"; StringOrInt otherValue = 10; Rust: enum StringOrInt { Str(String), Int(usize), } let my_value: StringOrInt = StringOrInt::Str("foo"); let other_value: StringOrInt = StringOrInt::Int(10); In Ceylon, you're right you don't need to name a "union", which IMO makes it much nicer, as I was able to use adhoc unions everywhere, e.g. inside streaming operations: [ for x in foos if (x.something()) "foo" else 10 ] The above "automatically" has type `[String | Integer]`. In Rust (and Kotlin) I would need to name a type just for this. Another disadvantage of Rust's approach is that the type variants are not types themselves. That's really annoying sometimes, e.g. you want to have a method that only handles one of the variants, but you can't (you need to pass the values the variant wraps separately, but that may be undesirable semantically as that would allow something that has no instance of the enum to also use the function).
- Zababa 5y agoI think there is a difference. Sum types allows you to choose between values, union types allows you to choose between types. The values of the sum types can contain themselves types, but they don't have to. On the other hand, you have to declare sum types beforehand, and you don't have that with union types. The equivalent of sum types in Ceylon seems to be enumerated types, which from what I understand you also have to declare beforehand. The difference with Rust is that Ceylon also has union types (Scala is the same, Typescript has unions but lacks proper sum types). As an interesting aside, Rust has what seem to be intersection types for trait bounds (fn toto<T: Trait1 + Trait2)(a: T)). I'm still not sure about the tradeoffs between union/intersection types and sum/product types. I think the difference is that "set types" are structural, while algebraic types are nominal, which comes with the usual tradeoffs, but I'm not sure.