4 ms·
I kind of consider algebraic data types (the combination of this style of enum (sum types) and structs (product types)) paired with pattern matching as the core
by pdpi 3y ago
I kind of consider algebraic data types (the combination of this style of enum (sum types) and structs (product types)) paired with pattern matching as the core feature set that any modern language must support. It makes for really simple, easy to follow code that’s much less error prone than the alternatives.
- the__alchemist 3y agoI joke to myself that I program with "struct and enum-oriented programming". I got it from Rust, but apply it to Python too. (Python enums aren't as ergonomic, and they can't wrap values, but they're a start)
- qsort 3y agoPython's equivalent of Rust's Enums would be the __match_args__ machinery rather than enums themselves, ironically. They aren't as ergonomic or type-safe, and rather surprisingly the match statement is not an expression in Python's grammar, but regardless of its problems the match statement is very powerful, even more so than static equivalents.
- GalaxySnail 3y agoIMO Python's equivalent of Rust's Enums would be `typing.Union` [1]. It is more ergonomic and type-safe, and mypy supports type narrowing [2] and exhaustiveness checking on it [3]. [1] https://docs.python.org/3/library/stdtypes.html#types-union https://docs.python.org/3/library/stdtypes.html#types-union [2] https://mypy.readthedocs.io/en/stable/type_narrowing.html https://mypy.readthedocs.io/en/stable/type_narrowing.html [3] https://docs.python.org/3/library/typing.html#typing.assert_never https://docs.python.org/3/library/typing.html#typing.assert_...
- boredumb 3y agoAbsolutely. It took me a few projects in Rust to sort of stumble on this and it can make some fairly complex business logic sit into nice matches that are trivial to run through.
- ewuhic 3y agoWhat would be the equivalent of these patterns in Go?
- fsdjkflsjfsoij 3y agoYou can't do the exact same thing in Go because Go doesn't have a way to define a sum type yet outside of generic constraints. The closest you can get is using an interface and a type switch but that won't give you exhaustive matching.
- newZWhoDis 3y agoProbably my favorite aspect of Swift as well, enums + payloads/associated types make for extremely safe and easy to understand code. Combine it with switches and you get compiler guarantees that every state is explicitly handled, and if you are in a particular state you always have the relevant child objects. I remember being shocked dart lacked this functionality when I tried out flutter.
- flohofwoe 3y agoI just wish Rust wouldn't have called those things 'enums' but 'tagged unions', would have saved us C peasants a lot of confusion when encountering them first ;)
- joshmarlow 3y agoC was my first language, and I actually have the opposite opinion - I suspect that calling them 'enums' helps adoption. My reasoning is that phrases like 'tagged unions' and 'algebraic datatypes' strike some developers as sounding very academic/ivory tower and so somewhat intimidating. I think this is really unfortunate (and is definitely not universal among developers). Being able to say 'Rust enums can carry arguments' - for some reason - sounds less intimidating and conveys the core feature.
- flohofwoe 3y agoI agree that something like 'sum type' sounds a bit too esoteric, but IMHO 'tagged union' is very descriptive. It's the same thing as a C union plus a tag indicating the currently active content (and that's also what the memory layout looks like under the hood). (but yeah, 'enum with arguments' also describes it very well)
- LoganDark 3y agoThey do point them out as tagged unions many times in the documentation. But the syntax `tagged_union Whatever {}` doesn't exactly have me jumping out of my seat.
- goku12 3y agoI sometimes wish Rust had combined structs and enums into a single concept - same an enum. Structs would have been unnecessary. The compiler can simply avoid the tag or the union when a pure struct or a pure (c-type) enum is required, respectively.
- bombela 3y ago> The compiler can simply avoid the tag or the union when a pure struct or a pure (c-type) enum is required, respectively. I had to try: pub enum Foo { Foo { a: i32 }, } impl Foo { pub fn new() -> Self { Foo::Foo { a: 42 } } pub fn get_a(Foo::Foo{a}: &Self) -> &i32 { a } } At opt level above zero (-C opt-level=1) the tag is elided: example::Foo::new: mov eax, 42 ret example::Foo::get_a: mov rax, rdi ret https://godbolt.org/z/qKzMqvhb7 https://godbolt.org/z/qKzMqvhb7
- goku12 3y agoThat really does make structs superfluous, doesn't it? The only additional thing needed is a syntax sugar, where the variant name can be avoided if there is only one variant.
- bombela 3y agoSyntactic sugar to avoid the variant where there is only one, not only where used, but also when declared: enum Foo { Foo{...} }, what to do with the second Foo. And what about FFI (foreign function interface) where you have to maintain ABI compatibility over time. Factor all of that in, and it turns out Rust already has syntax for all of that: struct Foo {}.