6 ms·
The problem with unions/enums is that is hard to pick a subset or superset of them, despite it will be not hard to add to any language. Is similar to projection
by mamcx 6y ago
The problem with unions/enums is that is hard to pick a subset or superset of them, despite it will be not hard to add to any language. Is similar to projection on the relational model (aka:select), sometimes I need:
enum Value {
Int32(i32),
Int64(i32),
Str(String),
}
fn only_int(of:Value[Int32, Int64]) -> Value.Str
And other times:
enum ExtraValue:Value {
Bool(bool),
}
This is analog to structs, where eventually is "discovered" that is nice to:
let user2 = User {
email: String::from("another@example.com"),
username: String::from("anotherusername567"),
active: user1.active,
sign_in_count: user1.sign_in_count,
};
let user2 = User {
email: String::from("another@example.com"),
username: String::from("anotherusername567"),
..user1
};
But somehow enums are still considered second-class in the algebraic type space.
- vmchale 6y agoThere's a hack! You can do data Value a = I32 Int32 a B Bool and then type Value1 = Value () type Value2 = Value Void as a hack
- mpartel 6y agoScala and TypeScript have (partial) answers to this. In your example, Scala 2 would let Int32 and Int64 inherit a trait that Str doesn't. TypeScript would let you write a union type Int32 | Int64 that doesn't include Str (or add ExtraValue), and I think Scala 3 will have something very similar.
- Ari_Rahikkala 6y agoI used to think that this was only ever going to be possible with some sort of incomprehensible type trickery that I would never be able to understand. Then TypeScript came along and showed me that no, actually, in a structural type system, it's just about as simple as you could imagine: type Foo = { kind: 'A', aItem: number } | { kind: 'B', bItem: string } | { kind: 'C' }; type SubsetFoo = Foo & { kind: 'B' | 'C' } type SupersetFoo = Foo | { kind: 'D', dItem: boolean }; I'm sure there are imperfections here. For a start, SubsetFoo's normalized form looks rather ugly when you mouse over it in VSCode. But it does get you the niceties of exhaustiveness checking and type-aware suggestions with control flow awareness, etc..
- skjfdoslifjeifj 6y agoI believe you can get a better normalized form of SubsetFoo by instead doing: type SubsetFoo = Extract<Foo, { kind: 'B' | 'C' }>;
- colanderman 6y agoOCaml has this for unions, see Polymorphic Variant Types here: https://www.ocaml.org/releases/4.11/htmlman/types.html https://www.ocaml.org/releases/4.11/htmlman/types.html