Live data from Hacker News

Using enums to represent state in Rust

corrode.dev

31–40 of 89 posts

Re: Using enums to represent state in Rust

#32
post #12

Rust ADTs and pattern matching are so much better than other mainstream languages I find that once my code compiles it actually is almost always correct. The next step is to encode your transition logic in the From impls between the enum structs and you've got yourself a first-rate state machine.

> Rust ADTs and pattern matching are so much better than other mainstream languages Pascal and Delphi have always had variant records as part of the language. Are these not "mainstream" enough, especially Delphi?

Those languages have other issues that make them weird to use. Rust has its fair share of weirdness as well, but most of that weirdness is just a direct side effect of the way that it is.

Re: Using enums to represent state in Rust

#33

Earlier quoted context omitted.

C 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 argume…

I 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)

They 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.

Re: Using enums to represent state in Rust

#34
post #26

Enums are fantastic. But they could be better! One thing Rust could really use are anonymous unions (A | B |C instead of E::A(A), E::B(B), E::C(C)). They are to enums what tuple types are to structs. Another thing that a new language designer might consider is a mechanism to control the layout. For example say I have a pair of nested enums enum A { A0(B), ... A15(B), } enum B { B0, ... B15, } The outer enum A can be…

You can do this by just implementing From and Into for your type - using the enum representation only for assignment or pattern matching. The more principled solution AIUI would be to have "patterns" as a first-class citizen within the language. Storing the tag 'out of band' is something you can only do as part of some larger object, in which case you can similarly have getters and setters that take or return enums a…

> From and Into for your type

It gets verbose fast when you are talking about all combinations of variants of an enum.

Re: Using enums to represent state in Rust

#35

As someone not versed in Rust I understand the point of the article is showing the Enum construct is powerful, but if you are worried about self-documenting code and want to avoid illegal state transitions, isn't it as simple as defining a map of (pseudocode here): {Active -> Inactive, Inactive -> Active, Active -> Suspended, Suspended -> Active, ...} And then having only _one_ function that mutates and checks for th…

How is that checked at compile time?

Re: Using enums to represent state in Rust

#36
post #4

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.

I 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 ;)

That would still be technically misleading, since enums don't necessarily have tags due to niche optimization. Eg `Option` is an enum but `Option>` does not have any tags; it uses the content being zero to represent None since `Box` cannot be zero.

Also, Rust does have actual tagged unions for C interop that you have to define yourself as a `struct` with an int field and a `union` field, just like in C.

Re: Using enums to represent state in Rust

#37
post #26

Enums are fantastic. But they could be better! One thing Rust could really use are anonymous unions (A | B |C instead of E::A(A), E::B(B), E::C(C)). They are to enums what tuple types are to structs. Another thing that a new language designer might consider is a mechanism to control the layout. For example say I have a pair of nested enums enum A { A0(B), ... A15(B), } enum B { B0, ... B15, } The outer enum A can be…

You can do this by just implementing From and Into for your type - using the enum representation only for assignment or pattern matching. The more principled solution AIUI would be to have "patterns" as a first-class citizen within the language. Storing the tag 'out of band' is something you can only do as part of some larger object, in which case you can similarly have getters and setters that take or return enums a…

Then what does this mean?

let x: u8 = E::Rest(0).into();

let y: E = x.into();

Re: Using enums to represent state in Rust

#38
post #26

Enums are fantastic. But they could be better! One thing Rust could really use are anonymous unions (A | B |C instead of E::A(A), E::B(B), E::C(C)). They are to enums what tuple types are to structs. Another thing that a new language designer might consider is a mechanism to control the layout. For example say I have a pair of nested enums enum A { A0(B), ... A15(B), } enum B { B0, ... B15, } The outer enum A can be…

You can do this by just implementing From and Into for your type - using the enum representation only for assignment or pattern matching. The more principled solution AIUI would be to have "patterns" as a first-class citizen within the language. Storing the tag 'out of band' is something you can only do as part of some larger object, in which case you can similarly have getters and setters that take or return enums a…

That's not equivalent. Notably if you have a `&[u8]` you can't transmute it to `&[E]`. It's also noisy when you have the enum as part of a larger struct, and can make encoding/decoding very verbose.

Re: Using enums to represent state in Rust

#39

Earlier quoted context omitted.

You can do this by just implementing From and Into for your type - using the enum representation only for assignment or pattern matching. The more principled solution AIUI would be to have "patterns" as a first-class citizen within the language. Storing the tag 'out of band' is something you can only do as part of some larger object, in which case you can similarly have getters and setters that take or return enums a…

> From and Into for your type It gets verbose fast when you are talking about all combinations of variants of an enum.

The point is that you only have to do it once, when defining the object. Everything else then happens via the From and Into implementations, which the compiler will generally be smart enough to inline. So it'll be just as efficient as working on the underlying u8.

Re: Using enums to represent state in Rust

#40
post #37

Earlier quoted context omitted.

You can do this by just implementing From and Into for your type - using the enum representation only for assignment or pattern matching. The more principled solution AIUI would be to have "patterns" as a first-class citizen within the language. Storing the tag 'out of band' is something you can only do as part of some larger object, in which case you can similarly have getters and setters that take or return enums a…

Then what does this mean? let x: u8 = E::Rest(0).into(); let y: E = x.into();

Bad example, that should panic (in a perfect world it should be a compile error). The invariant of the type is that `E::Rest` cannot hold zero.
Post reply on HN