I read documentation about size of enums in Swift and here is my understanding:
This simple one only hold a 'tag' to differentiate cases, which is by default an UInt8
value, i.e. small = 0
, medium = 1
and so on. So, Size
's size is 1 byte, which can be verified with MemoryLayout<Size>.size
. I also noted that if an enum has more than 255 cases, obviously the tag size is upgraded to 2 bytes.
enum Size {
case small
case medium
case large
}
Second case, if an enum has associated values it behaves like a union. In this case the enum size is the size of the tag plus the size of the largest associated value. In the following example the size is 1 byte + 16 bytes (String) so 17 bytes, which can also be verified with MemoryLayout
.
enum Value {
case int(Int)
case double(Double)
case string(String)
case bool(Bool)
}
Last case, as Swift is a safe language references are always valid using standard non-unsafe Swift code, i.e always pointing to a value in memory. This allows the compiler to optimise such enum when T
is a reference type:
enum Opt<T> {
case none
case some(T)
}
Here an instance of type T
cannot by nil
(NULL) so the compiler uses this special value for the none
case, hence Opt
is of size 8 bytes instead of 9 bytes when T
is a reference type. This optimisation is raised in this SO question about Rust which I believe has the same behaviour has Swift concerning enums.
For instance with this simple reference type, MemoryLayout
returns a size of 8 bytes:
class Person {
var name: String
init(name: String) {
self.name = name
}
}
let p = Opt.some(Person(name: "Bob")) // 8 bytes
Question
What I cannot figure out is the size of this enum (still when T is a reference type):
enum Opt<T> {
case none
case secondNone
case some(T)
}
Why this one is also 8 bytes, according to MemoryLayout
?
In my understanding it should be 9 bytes. The NULL optimisation is only possible because none
can be represented by NULL but there is no 'second' NULL value for secondNone
in my example, so a tag should be required here to differentiate the cases.
Does the compiler automatically turns this enum into a reference type (similar to an indirect
enum) because of this? This would explain the 8 bytes size. How can I verify this last hypothese?
-O
optimisation. – Moue