
Virtual Structs Part 1: Where Rust’s Enum Shines - Manishearth
http://smallcultfollowing.com/babysteps/blog/2015/05/05/where-rusts-enum-shines/
======
saosebastiao
Rust was the first language in which I used tagged unions. While I can't say
that I use Rust at the moment (not mature enough and too low-level for my
current needs), I found pattern matching and tagged unions so beneficial and
practical that now I refuse to use any language that doesn't have them.
Currently I'm writing a bunch of code in F#.

I don't know what the language of the future will be but I can't imagine it
not having an ML heritage.

~~~
gnuvince
I needed to write a small AST in Java, and I actually had to write the
definition in ML on a sheet of paper to see how to do it. It's so weird that
so many languages don't have sum types.

~~~
sixbrx
What's too bad is that Java had a chance to handle alternatives properly as
sum types, when enums were being added. But the designers chose instead of sum
types, to add them as yet another kind of "object" that have to have a common
constructor (and thus the exact same backing data) and methods. So basically
all the variants have to be of the same "shape". Very disappointing!

------
digikata
In C++ (and C for that matter) you use an enum + union in a struct to
implement these virtual structs, then all the criticisms of pointer slicing,
and not being able to pass by value go away. You do have to manage all that
manually though, so Rust would definitely have the very nice advantage of
having language support to do that cleanly.

------
sepeth
FP languages have algebraic data types for this. Why do they call it virtual
structs? How are they different than ADTs?

~~~
eddyb
"Virtual Structs" is a name for a potential feature that may expose some sort
of structural inheritance or subtyping.

The name is not used for the current "enum" feature, which is one of the few
ADTs in Rust (there's also "struct" and tuples - not sure what else
qualifies).

~~~
pdpi
enum gives you sum types, struct/tuples provide product types. That's pretty
vanilla ADTs sorted. GADTs are a whole other can of worms though.

------
jarrettc
I'm hoping the next post will talk about this use case: Suppose I have an enum
called "Canine" and I want each of its variants to implement a different
"bark" method. Currently, as far as I know, I have to write a match statement
dispatching "bark" to each "Canine" variant. If I have "bark" and "growl," I
have to write two match statements, and so on for each method that needs to be
dispatched to different variants.

So it's a lot of boilerplate. I think it can be slimmed down with a macro, but
still.

You might think traits rather than enums are the way to go here. Sometimes
that may be true. But often, an enum is far preferable because in Rust, a
trait is not a type, but an enum is. That means you cannot, for example, have
a "Vec<CanineTrait>," but you can have a "Vec<CanineEnum>."

~~~
dcb18
A trait is a type, but the type does not have a size, which is the reason it
is not possible to store a trait instance directly in a Vec (or any other
place needing a sized type). It is possible to store a pointer to a trait
object in a Vec, which would look like Vec<Box<CanineTrait>>.

~~~
jarrettc
Ah, my mistake. So would I be correct in saying that a trait is a type, but it
does not necessarily implement the Sized trait, and if it does not, then it
cannot be allocated directly on the stack?

Also, I've been wondering something about dereferencing a Box where the inner
type is just a trait. If I dereference a Box<CanineTrait> and call "bark," how
is the correct implementation found at runtime? Is there a vtable or something
analogous?

~~~
losvedir
> If I dereference a Box<CanineTrait> and call "bark," how is the correct
> implementation found at runtime? Is there a vtable or something analogous?

I think a vtable. It's my understanding that "trait objects" (boxed traits)
are how you implement dynamic dispatch in rust. If instead you were talking
about a `fn foo<T: CanineTrait>(x: T) { ... }` trait bound (the more common
case), there will be monomorphization and static dispatch.

Source: [http://doc.rust-lang.org/1.0.0-beta/book/static-and-
dynamic-...](http://doc.rust-lang.org/1.0.0-beta/book/static-and-dynamic-
dispatch.html)

~~~
steveklabnik
After the beta landed, I re-did the TOC for the book, and so this information
will be at [http://doc.rust-lang.org/nightly/book/trait-
objects.html](http://doc.rust-lang.org/nightly/book/trait-objects.html) in the
future. (where nightly = 1.0.0, of course)

------
st3fan
Yup. This is also one of my favourite language features in Swift.

------
halayli
An enum, short for enumeration, shouldn't hold data, else don't call it an
enum. It's no longer an enumeration, it's a data structure.

~~~
kinghajj
Rust's enum is a natural extension to the common notion of enumerated types to
ADTs:
[http://en.wikipedia.org/wiki/Enumerated_type#Algebraic_data_...](http://en.wikipedia.org/wiki/Enumerated_type#Algebraic_data_type_in_functional_programming).

~~~
halayli
If Rust wants to win C/C++ developers, it shouldn't surprise them a lot.

~~~
barosl
I would say that the reason it is named `enum` is exactly _not_ to surprise
them. While learning Haskell, I had used `data` several times, but never
grokked its true meaning. The naming of `enum` in Rust helped me finally
understand what ADTs are, and thus also made me truly understand what
Haskell's `data` is. I really appreciate Rust for trying to introduce a
certain concept with the existing names.

