Home > Software engineering >  Is it correct to convert from computed property to lazy variable under constant struct?
Is it correct to convert from computed property to lazy variable under constant struct?

Time:02-28

I wanted to change my code to use lazy variable instead of Computed property.
this code works

struct Point {
    var x = 0.0, y = 0.0
}
struct Size {
    var width = 10.0, height = 10.0
}
struct Rect {
    var origin = Point()
    var size = Size()
    var center: Point{
        get{
            let centerX = origin.x   (size.width / 2)
            let centerY = origin.y   (size.height / 2)
            return Point(x: centerX, y: centerY)
        }
    }}
let shape = Rect()
print(shape.center)

But this code produces an error

struct Point {
    var x = 0.0, y = 0.0
}
struct Size {
    var width = 10.0, height = 10.0
}
struct Rect {
    var origin = Point()
    var size = Size()
    lazy var center = Point(x: origin.x   (size.width / 2), y: origin.y   (size.height / 2)) 
}
let shape = Rect()
print(shape.center)  

I can fix the error if I changed let shape = Rect() to variable type var shape = Rect() OR when I change Rect to class instead of struct
What is wrong with my code and why does it give me error?

CodePudding user response:

Notice that getting a lazy property potentially changes the struct value. Its state could change from "the lazy property has not been computed" to "the lazy property has been computed". This is why the getters of lazy properties are mutating.

A let constant does not allow its value to change, so you can't use mutating members on it. vars do, so that's why using a var makes your code compile.

Changing Rect to a class makes it a reference type. This means that the let constant shape stores a reference to an instance of Rect, and this reference cannot be changed (e.g. you can't do shape = someOtherRect afterwards). However, the instance of Rect can still be changed (remember that the let constant is only storing a reference to it), and so getting a lazy property is fine on shape, when Rect is a class. Doing this will only potentially change the instance of Rect.

In my opinion, it is not appropriate to change Rect.center to a lazy property. After the first use of its getter, center will stay unchanged even if you change origin or size:

var shape = Rect()
print(shape.center)
shape.size = Size(width: 100, height: 100)
// now shape.center is incorrect!
  • Related