4 ms·
To extend on what Steve mentioned, `union` in Rust is a C-style union, but because the type carries no information on what variant the underlying bits represent
by estebank 6y ago
To extend on what Steve mentioned, `union` in Rust is a C-style union, but because the type carries no information on what variant the underlying bits represent, accessing them is `unsafe`[1]. On the other hand, `enum`s in Rust are tagged unions, they reserve some data for the typesystem to determine at runtime which variant any given instance corresponds to. Because of that you can't interpret the T as an E with an enum, but you can with an union.
[1]: https://doc.rust-lang.org/reference/items/unions.html https://doc.rust-lang.org/reference/items/unions.html
- ziml77 6y agoAnd to add onto that, you can also use a Rust enum like a traditional enum: enum Foo { OptionA, OptionB, OptionC, } enum Bar { OptionA = 1, OptionB = 2, OptionC = 4, }
- scoutt 6y ago> to determine at runtime I didn't know this. How is determined? Is there any code inserted by the compiler to do this? What's the overhead of using Result<T, E>?
- estebank 6y agoTL;DR: the overhead for enums that don't have an inordinate amount of variants is about 8 bytes, but can be zero in special cases. > What's the overhead of using Result<T, E>? Enough bits (+ padding) to discriminate between all the variants, as any tagged union would, modulo some tricks for niche optimization. For example, Result<i64, u64> is 16 bytes in memory because it needs 8 bytes to represent either a i64 or an u64, plus another 8 bytes to determine whether it is an Ok or an Err. You can think of it as a struct Enum { variant: usize, bytes: [u8; N], } The niche optimization I mentioned applies for things like Option<NonZeroI64>, where NonZeroI64 fits in 8 bytes but the compiler can ensure that the bitpattern corresponding to the 0 value will never be used, so it can use that to differentiate between Some and None. https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=6c4de0addbabb43ff279af2b8333be56 https://play.rust-lang.org/?version=stable&mode=debug&editio...
- scoutt 6y agoThank you. Regarding size, from an embedded perspective, do you think all these enums, in a very deep call stack can, ultimately, overflow my stack? Because for every function call there should be 8, or 16 or 24 or N bytes of stack-allocated space to hold these enums. Is this something embedded Rust developers keep in mind? Or perhaps worry about the extra copies it has to make when functions return? Regarding code: because of the "to determine at runtime" of your parent comment, I thought there could be some runtime checks (extra code) for handling enums.
- estebank 6y ago> Regarding size, from an embedded perspective, do you think all these enums, in a very deep call stack can, ultimately, overflow my stack? Because for every function call there should be 8, or 16 or 24 or N bytes of stack-allocated space to hold these enums. Is this something embedded Rust developers keep in mind? Or perhaps worry about the extra copies it has to make when functions return? I don't think I have come across any conversation by embedded developers foregoing enums because of that, but anecdotally that space does seem to rely on type state machines a bit more than others, which have no runtime memory cost. A bigger cost consideration is if you have an enum with variants that have wildly different sizes, making the enum big for all cases, whether it is necessary or not. We have a lint to encourage you to Box wildly diverging variants, but that might not be possible if you don't have an allocator. > Regarding code: because of the "to determine at runtime" of your parent comment, I thought there could be some runtime checks (extra code) for handling enums. Yeah, I figured that's what happened and I should be more careful with my wording.