# Enum with or without Box?

**URL:** <https://users.rust-lang.org/t/enum-with-or-without-box/15746>\
**Category:** help\
**Created:** [February 19, 2018, 6:54pm UTC](https://users.rust-lang.org/t/enum-with-or-without-box/15746 "2018-02-19T18:54:23Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![grubber](https://avatars.discourse-cdn.com/v4/letter/g/7cd45c/32.png) [@grubber](https://users.rust-lang.org/u/grubber)\
**Post date:** [February 19, 2018, 6:54pm UTC](https://users.rust-lang.org/t/enum-with-or-without-box/15746/1 "2018-02-19T18:54:23Z")

</div>

Should I always prefer the enum variants with boxed types to ones without boxes?

```
enum A {
    A((u64, u64, u64)),
}

enum B {
    B(Box<(u64, u64, u64)>),
}

```

---

<div class="post-metadata">

**Author:** ![aschampion](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/aschampion/32/4578_2.png) [@aschampion](https://users.rust-lang.org/u/aschampion)\
**Post date:** [February 19, 2018, 7:18pm UTC](https://users.rust-lang.org/t/enum-with-or-without-box/15746/2 "2018-02-19T19:18:20Z")

</div>

The contained tuple in `A` lives on the stack (if the enum lives on the stack), while in `B` it always lives on the heap. In memory an `A` value is going to contain the enum tag plus the 24 bytes for the tuple, while `B` will contain the tag and a pointer for the `Box`.

Which one you prefer depends firstly on where you want the tuple to live and secondly on your needs regarding the memory size and layout of the enum. If you don't know about these things or aren't concerned with them, you most likely prefer `A`.

---

<div class="post-metadata">

**Author:** ![grubber](https://avatars.discourse-cdn.com/v4/letter/g/7cd45c/32.png) [@grubber](https://users.rust-lang.org/u/grubber)\
**Post date:** [February 19, 2018, 7:19pm UTC](https://users.rust-lang.org/t/enum-with-or-without-box/15746/3 "2018-02-19T19:19:50Z")

</div>

What changes if I want to store there big structures, a couple of them in a tuple inside the enum variants?

---

<div class="post-metadata">

**Author:** ![shanedora](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/shanedora/32/6593_2.png) [@shanedora](https://users.rust-lang.org/u/shanedora)\
**Post date:** [February 19, 2018, 9:58pm UTC](https://users.rust-lang.org/t/enum-with-or-without-box/15746/4 "2018-02-19T21:58:27Z")

</div>

@aschampion  
How are these packed (byte align) in memory? For example these enums (A and B) are they byte aligned in both cases?

---

<div class="post-metadata">

**Author:** ![vitalyd](https://avatars.discourse-cdn.com/v4/letter/v/edb3f5/32.png) [@vitalyd](https://users.rust-lang.org/u/vitalyd)\
**Post date:** [February 20, 2018, 2:20am UTC](https://users.rust-lang.org/t/enum-with-or-without-box/15746/5 "2018-02-20T02:20:34Z")

</div>

The size of the enum will be the size of the largest variant, plus a discriminant (if one is needed, but that will be the case for virtually any enum with more than 1 variant).

Similarly, the alignment will be of the largest variant. In the case of A and B above, they’re both 8 byte aligned on 64bit, and B would be 4 byte aligned on 32bit.

As for @grubber’s question, the answer depends 🙂. A couple of big considerations I’d take into account:

- if there’s one variant outsizing all the rest, and it’s not the dominant variant in terms of frequency, I’d box it.
- if I’m copying (or moving) them around a lot more than accessing their data, I’d consider boxing the larger variants.

Otherwise, I wouldn’t box. Again, these are pretty general. The gist is I’d tailor its size based on how I’m using them, and make sure a large variant (or two) don’t make me pay an unwanted perf penalty.

---

<div class="post-metadata">

**Author:** ![grubber](https://avatars.discourse-cdn.com/v4/letter/g/7cd45c/32.png) [@grubber](https://users.rust-lang.org/u/grubber)\
**Post date:** [February 20, 2018, 7:15am UTC](https://users.rust-lang.org/t/enum-with-or-without-box/15746/6 "2018-02-20T07:15:48Z")

</div>

What about a enum of about 10 variants with parameters count 1 to 3 (without tuple), and each parameter is a big structure of heap-allocated collections (`String`, `Vec` and so on). Should I use `Box` in this case?

---

<div class="post-metadata">

**Author:** ![vitalyd](https://avatars.discourse-cdn.com/v4/letter/v/edb3f5/32.png) [@vitalyd](https://users.rust-lang.org/u/vitalyd)\
**Post date:** [February 20, 2018, 11:08am UTC](https://users.rust-lang.org/t/enum-with-or-without-box/15746/7 "2018-02-20T11:08:12Z")

</div>

It’s hard to say without knowing how you’re using this enum. 3 Vecs or Strings is a healthy 72 bytes on a 64bit system - copying that around a lot might be noticeable.

If in doubt, stick to unboxed layout and then see if profiling shows hotspots associated with copying/moving this enum around.

---

<div class="post-metadata">

**Author:** ![grubber](https://avatars.discourse-cdn.com/v4/letter/g/7cd45c/32.png) [@grubber](https://users.rust-lang.org/u/grubber)\
**Post date:** [February 20, 2018, 11:21am UTC](https://users.rust-lang.org/t/enum-with-or-without-box/15746/8 "2018-02-20T11:21:51Z")

</div>

The thing is that the `clippy` warned me that I should use `Box`. But, according to its logic, I should use enums with Boxes all the time if my enum consists of big objects. Is it correct?

P.S. I am sending this enum to the `mpsc::channel`.

---

<div class="post-metadata">

**Author:** ![vitalyd](https://avatars.discourse-cdn.com/v4/letter/v/edb3f5/32.png) [@vitalyd](https://users.rust-lang.org/u/vitalyd)\
**Post date:** [February 20, 2018, 12:00pm UTC](https://users.rust-lang.org/t/enum-with-or-without-box/15746/9 "2018-02-20T12:00:08Z")

</div>

Well how big is the enum exactly? For clippy to warn on it, I believe there has to be (by default) at least a 200 byte difference in size between the smallest and largest variants. That’s certainly more than just 1-3 Vec/String values 🙂

---

<div class="post-metadata">

**Author:** ![grubber](https://avatars.discourse-cdn.com/v4/letter/g/7cd45c/32.png) [@grubber](https://users.rust-lang.org/u/grubber)\
**Post date:** [February 20, 2018, 12:15pm UTC](https://users.rust-lang.org/t/enum-with-or-without-box/15746/10 "2018-02-20T12:15:56Z")

</div>

You understood me wrong.

I meant this:

```
struct A {
    a: Vec<String>,
    b: Vec<SomeOtherBigStructure>,
    c: String,
    d: HashMap<>,
}

struct B {
// ... the same as above
}

struct C {
// ... the same as above
}

enum E {
    A(A, C),
    B(A, B),
    C(A, B, C)
}

```

And so on.

---

<div class="post-metadata">

**Author:** ![broken-pen](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/broken-pen/32/47429_2.png) [@broken-pen](https://users.rust-lang.org/u/broken-pen)\
**Post date:** [February 20, 2018, 12:26pm UTC](https://users.rust-lang.org/t/enum-with-or-without-box/15746/11 "2018-02-20T12:26:43Z")

</div>

Note that `Vec<SomeOtherBigStructure>` allocates all of these big structures on the heap. So while each `SomeOtherBigStructure` may be really big, `Vec<SomeOtherBigStructure>` will almost certainly be 24 bytes large. (3 usize values: pointer, length, capacity)

---

<div class="post-metadata">

**Author:** ![vitalyd](https://avatars.discourse-cdn.com/v4/letter/v/edb3f5/32.png) [@vitalyd](https://users.rust-lang.org/u/vitalyd)\
**Post date:** [February 20, 2018, 12:36pm UTC](https://users.rust-lang.org/t/enum-with-or-without-box/15746/12 "2018-02-20T12:36:03Z")

</div>

Ok, that's a bulky enum indeed. How is the enum used though? We keep talking about its size, which is important, but you've not said anything about how you're using it. In particular, are you copying/moving it around a lot?

If you own the structs, you may also be able to re-organize their layout to better fit usage characteristics (e.g. move some of _their_ parts to the heap, rather than moving the entire struct to the heap inside the enum). But really, it's hard to speculate without having more concrete information.

---

<div class="post-metadata">

**Author:** ![grubber](https://avatars.discourse-cdn.com/v4/letter/g/7cd45c/32.png) [@grubber](https://users.rust-lang.org/u/grubber)\
**Post date:** [February 20, 2018, 12:48pm UTC](https://users.rust-lang.org/t/enum-with-or-without-box/15746/13 "2018-02-20T12:48:05Z")

</div>

I told that, you missed 🙂  
I am sending object of this enum to the mpsc::channel.

---

<div class="post-metadata">

**Author:** ![vitalyd](https://avatars.discourse-cdn.com/v4/letter/v/edb3f5/32.png) [@vitalyd](https://users.rust-lang.org/u/vitalyd)\
**Post date:** [February 20, 2018, 12:52pm UTC](https://users.rust-lang.org/t/enum-with-or-without-box/15746/14 "2018-02-20T12:52:19Z")

</div>

Nope, I didn't miss that 🙂. What you've not said is whether you construct this enum right before sending it on the channel or whether you're taking it (moving or copying) from somewhere. You've also not said how you're accessing the data of the enum on the receiver side of the channel. You've also not indicated whether any of the 10 variants are more common/frequent than others, and whether they're the bulkier of the bunch.

---

<div class="post-metadata">

**Author:** ![grubber](https://avatars.discourse-cdn.com/v4/letter/g/7cd45c/32.png) [@grubber](https://users.rust-lang.org/u/grubber)\
**Post date:** [February 20, 2018, 1:06pm UTC](https://users.rust-lang.org/t/enum-with-or-without-box/15746/15 "2018-02-20T13:06:35Z")

</div>

All of them are nearly equally frequency used. I construct these objects and passing to the `mpsc::channel` immediately. The enum variants consist of event-related objects which I send on some event. I access this data simply: I receive enum objects from a `mpsc::channel`'s receiver and then match them with unpacking.

---

<div class="post-metadata">

**Author:** ![vitalyd](https://avatars.discourse-cdn.com/v4/letter/v/edb3f5/32.png) [@vitalyd](https://users.rust-lang.org/u/vitalyd)\
**Post date:** [February 20, 2018, 1:15pm UTC](https://users.rust-lang.org/t/enum-with-or-without-box/15746/16 "2018-02-20T13:15:56Z")

</div>

Ok cool. In this case, it would seem ideal if we had placement construction where the enum can be constructed right in the channel. There’s some support for placement-new in nightly (I believe) but I don’t know offhand if channels have support for it.

The reason for this is because there’s some risk that the enum will be first constructed on the stack and then copied into the channel, which is wasteful. But it’s possible LLVM can optimize this away - only way to tell is by looking at the assembly. And even if this optimization does kick in, it’s conceivable that it’ll break with slightly different code shape.

However, unless you use the box syntax, there’s no guarantee this won’t happen with Box either! So in that regard, I’d stick with non-box storage to start. If you see the copying is showing up in profiling, you can try boxing it up and seeing what happens. Avoiding the box has an extra advantage of not going through the allocator two extra times (to alloc and then to free).

---

<div class="post-metadata">

**Author:** ![H2CO3](https://avatars.discourse-cdn.com/v4/letter/h/b5ac83/32.png) [@H2CO3](https://users.rust-lang.org/u/H2CO3)\
**Post date:** [February 24, 2018, 11:11am UTC](https://users.rust-lang.org/t/enum-with-or-without-box/15746/17 "2018-02-24T11:11:37Z")

</div>

> [@grubber](#):
>
> Should I always prefer the enum variants with boxed types to ones without boxes?

Definitely not **always** ; why would you create a pointer "just for the sake of it" when you don't _need_ one? You need to decide whether you _need_ a `Box` (e.g. if your `enum` is recursive via its variants' associated data, or if the type you are putting in the `enum` needs to have a stable address as with some OS-specific mutexes, etc.), and if you do, then sure, go for it — but I would actually prefer defaulting to direct embedding. (In most cases, the type system will tell you if that won't work, and then you can change it.)

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/steffahn/32/47569_2.png) [@steffahn](https://users.rust-lang.org/u/steffahn)\
**Post date:** [January 12, 2023, 8:46am UTC](https://users.rust-lang.org/t/enum-with-or-without-box/15746/18 "2023-01-12T08:46:42Z")

</div>


