Lazy Calculated Variable

Lazy calculated variable

From the docs:

Modifying Value Types from Within Instance Methods

Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods.

However, if you need to modify the properties of your structure or enumeration within a particular method, you can opt in to mutating behavior for that method. The method can then mutate (that is, change) its properties from within the method, and any changes that it makes are written back to the original structure when the method ends. The method can also assign a completely new instance to its implicit self property, and this new instance will replace the existing one when the method ends.


So then, a struct cannot modify itself unless the function doing the modification is flagged as mutating. This means you need to define a proper get function for the property.

var magnitude: Double {
mutating get {
if magnitudeActual < 0.0 {
NSLog("Recalc") // just to make sure it's caching the result properly.
magnitudeActual = sqrt(x * x + y * y)
}
return magnitudeActual
}
}

Now we can do this

var v = Vector(3, 4)
v.magnitude // Recalc 5
v.magnitude // 5

v.x = 5
v.y = 12
v.magnitude // Recalc 13

Swift function vs lazy var vs computed property - difference?

  • lazy vars are actually stored properties, so you can't put it in extensions or anywhere stored properties are not allowed.
  • The getter for computed properties is run every time you refer to that property. This can be significant especially if the getter is time-consuming or has side-effects to other parts of the code.
  • The getter for lazy vars are only run when the property is first referred to and never again.
  • lazy vars are variables. You can mutate them.
  • Computed properties can optionally have a setter, so sometimes they are read-only.
  • Using a function like that is very similar to a read only computed property. You just have to add () when getting its value.

Is it correct to convert from computed property to lazy variable under constant struct?

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!

Swift: why lazy, computed property, and property observer can not be let

Lazy properties : You must always declare a lazy property as a variable (with the var keyword), because its initial value might not be retrieved until after instance initialization completes. Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy.

computed property : whereas computed properties calculate (rather than store) a value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly.

property observer : property observers is to monitor changes in a property’s value, if you define it let then how you can monitor changes because let is one type of constant which you can not change after init.

Why lazy variables / computed properties, not just methods

Answer: Lazy variables exist to cut on loading time (i.e. for optimization reasons). Some variables aren't needed immediately unless explicitly called for. And they, like Math.pi might take a while to compute. So the application may start computing them in a background thread when the most important user-initiated operations have finished.

As for computed properties, I think it's more of a language decision. Objective-C introduced properties a long time ago, and they've always been technically 'computed' (with getters and setters, be it automatically synthesized / explicitly implemented), and it was (and is) a wildly accepted feature. Why? I don't know for sure. Maybe there isn't 'one clear answer' to this question. Like I said, I believe it's a language decision, not something that can be rationalized completely.

For me personally, it feels more intuitive to both read and write a property using the same .property syntax, rather than property() and setProperty(_: Property) functions. This is an abstraction, and language abstractions exist for comfort / ease-of-use. Your examples are highly contrived, and computed properties are used by the thousands across Apple's frameworks. Not each computed property needs to be extremely time consuming, and most of them are in fact practically instant; thus they are abstracted to feel so.

When you think about it, everything is technically computed. Even if you, for example, set an integer value directly to a structure field, there are things that need to happen on a lower scale. These low level computations are abstracted to feel like non-computed, concrete entities, when in reality they are. It all boils down to abstraction.

Swift Lazy Variables that Load more than Once (Computed Properties?)

You can create something similar to the Objective-C method using a computed property backed by an optional variable.

var _fetchedResultsController: NSFetchedResultsController?

var fetchedResultsController: NSFetchedResultsController {
get {
if _fetchedResultsController != nil {
return _fetchedResultsController!
}
//create the fetched results controller...
return _fetchedResultsController!
}
}

Setting a variable to a defined lazy var within a UIView closure cause reference problems

You were intended to use computed property of swift. But didn’t get it right. Your profile label should have been defined as follows.

var profileLabel: UILabel {
get {
let label = UILabel()
label.font = .displayNameLabel
label.textColor = .profileLabel
label.numberOfLines = .numberOfLines
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
return label
}
}


Related Topics



Leave a reply



Submit