49

I can think of many places where unions in C help are useful and they save memory. As Rust is a system programming language, why doesn't it support unions?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
unnamed_addr
  • 1,217
  • 2
  • 12
  • 14

2 Answers2

92

Unions were added to the language in (RFC 1444), and they are stable as of Rust 1.19.0. They require usage of unsafe blocks.

Raw unions are not memory-safe (as there is no way for the compiler to guarantee that you always read the correct type (that is, the most recently written type) from the union). One of the goals of Rust is to create a low-level language with memory safety; since unions are not compatible with that goal, they were not included in Rust 1.0.

Instead, Rust has enums, which provide most of the advantages of unions in exchange for a small memory usage, but which are memory safe since the enumeration value always keeps track of which particular type it contains.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Mankarse
  • 39,818
  • 11
  • 97
  • 141
  • "in exchange for a small memory usage", I just want to add that this extra memory is solely the identifier, which is 1 byte (as long there are no more than 256 variants). – Rein F Dec 27 '20 at 16:40
  • 8
    @ReinF although in practice I expect that extra byte will often get padded to the machine word size for efficiency. – Nick Treleaven Jan 04 '21 at 17:27
48

Rust has tagged unions in the form of its algebraic data types, enum:

enum Foo {
    Bar(i32),
    Baz,
    Quux {
        misc: A,
        ellaneous: B,
        fields: C,
    },
}

A Foo there can be either a Bar with an attached i32, a Baz with no additional data or a Quux with those three miscellaneous fields. This is a tagged union—the size of an enum will not exceed the largest of its variants plus as much as is needed for the tag (typically one byte, but I guess it’s possible to have more variants than fit in one byte), and in certain cases where it can be optimised (like Option<&T> where a memory address of 0 is not legal for the Some variant and so can be used to represent the None variant) the variant is squeezed into the value.


What Rust does not have is untagged unions as in C. Why? Because they’re fundamentally unsafe, and safety is paramount for Rust. If you still want something like that, it’s perfectly possible to create a wrapper around the unsafe code that you will wind up with with things like transmutation happening, but you simply don’t need untagged unions in normal life.

Rust does now support untagged unions as an unsafe concept; as of 1.19.0.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Chris Morgan
  • 86,207
  • 24
  • 208
  • 215
  • 10
    The tag can be larger than one byte even if you have only two variants (e.g. `enum X { S(i32), U(u32) }` is eight bytes), because of alignment. Technically it's one byte with three bytes padding, but the end result is the same. –  Mar 25 '15 at 08:26