I wanted to know which of the following occupies more memory
struct Constants
{
var age = 10
}
or
enum Constants
{
case age = 10
}
I also wanted to know the difference between enum
and #define
in terms of memory storage. Could anyone help me out?
Your struct would occupy the size of an Int, so on a recent Mac platform 64 bits (8 bytes). Your enumeration would normally occupy the size of an UInt8 so 8 bits (1 byte) but in this special case of a one case enum the size is 0 bit.
An enumeration internally stores an integer value to match the cases against.
For instance this enum:
enum Direction {
case east, west, south, north
}
is roughly equivalent to:
struct Direction {
private var rawValue: UInt8
private init(_ rawValue: UInt8) {
self.rawValue = rawValue
}
static var east: Direction { Direction(0) }
static var west: Direction { Direction(1) }
static var south: Direction { Direction(2) }
static var north: Direction { Direction(3) }
}
with some auto-generated methods to enable use in switch
and if blocks, and some compiler magic to support switch statements exhaustivity.
Note that the rawValue is UInt8
so any Swift enumeration with less than 256 cases and without any associated value is 8 bits (1 byte).
If your enumeration has more than 255 cases the rawValue
type upgrades to UInt16
, and so on.
An enum containing an associated value is much more memory consuming, its size is the size of the rawValue + the size of the largest associated values.
For instance:
enum Shape {
case circle(radius: Double)
case rectangle(width: Double, height: Double)
}
This enum would be 136bits (17bytes): 2 * size(Double
) + size(UInt8
) because the rectangle case has the largest associated values which are two Double
s.
In your case you defined an enum with custom raw values of type Int
. Contrary to an enum with associated values this does not change the size of the enum at all. The Compiler just synthesises a computed property that return the custom rawValue
.
For instance this enum with a String rawValue
is still 1byte:
enum HelloWorld: String {
case hello = "Hello, "
case world = "world!"
}
// "Equivalent" to...
enum HelloWorld {
case hello
case world
var rawValue: String {
switch self {
case .hello:
return "Hello, "
case .world:
return "world!"
}
}
}
You can check the size of anything with:
MemoryLayout<TypeToSize>.size // for a type
MemoryLayout.size(ofValue: yourValue) /* for an instance */
Be careful with reference types though, for instance a class is a reference type so it has the size of a pointer so 64 bits (8 bytes) on recent Mac platforms.
If your enumeration has lots of heavy associated types you can turn it into a reference type with the indirect
keyword so its size is one of a pointer but this cost you the dereferencing operation.
In Swift the proper way to create a namespace is to define an enum with no case and only static properties.
The advantage of an enum over a struct is that such an enum cannot be instantiated which is the indented behaviour for a namespace.
In your case the proper way is:
enum Constants {
static var age = 10
}
// Example of use...
let birthYear = 2020 - Constants.age
An empty enum or an enum with only one case has a size of 0 bit. However, the static property needs to be stored at some point, this cost you at least the size of the Int
value.
#define
only exists in Objective-C AFAIK, not in Swift, so the canonic way to replicate this pattern is through the case-less enum (avoid global variables).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With