I have an immutable struct that I'm working with, and I'm trying to create a property that is not a computed value, however it's assignation requires the values of previously assigned properties.
(Wow mouthful).
The property I'm struggling with is perimeter: Int
// Floor made out of square tiles.
struct Floor {
let
size: (x: Int, y: Int), // How many tiles in the floor
tilePerimeter: Int,
// Calculate entire floor's perimeter based on tile quantity and perimeter:
lazy let perimeter: Int = {
let
t4th = self.tilePerimeter / 4, // Tile width / length
sx = self.size.x * t4th, // All X tiles' length
sy = self.size.y * t4th // All Y tiles' width
return (sx * 2) + (sy * 2) // Perimeter calc
}()
};
Unfortunately, Swift will not let me use a lazy let
.. So my workaround here was to just make a computed var
with only a getter... but if this calculation took a long time (loading an image or complex math) then it would be called many times, when really it is only needed to call once
So my actual workaround was to just to create an initializer and assign the perimeter there... only some of my structs have MANY properties, and not creating an initializer for structs is part of the Swiftiness that I love.
I know that I could just make this a lazy var
and instantiate the struct as let
, but that seems confusing and error-prone.
Is there a way to do this where I can retain immutability, performance, and Swiftiness? And also, what is the reason for there not being allowed to use lazy let
?
Maybe you could use lazy var
after all:
lazy private(set) var perimeter: Int = {
...
}()
A read-only var
gets you closer to the desired let
semantics.
You can force this to be computed only once while still using a read-only computed var by using an optional private var with a default of nil
, much in the same way as singleton objects are implemented.
// Floor made out of square tiles.
struct Floor {
private var computedPerimeter: Int? = nil
let
size: (x: Int, y: Int), // How many tiles in the floor
tilePerimeter: Int
// Calculate entire floor's perimeter based on tile quantity and perimeter:
var perimeter: Int {
mutating get {
if computedPerimeter == nil {
let
t4th = self.tilePerimeter / 4, // Tile width / length
sx = self.size.x * t4th, // All X tiles' length
sy = self.size.y * t4th // All Y tiles' width
computedPerimeter = ((sx * 2) + (sy * 2)) // Perimeter calc
}
return computedPerimeter!
}
}
};
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