Are Swift constants lazy by default?
Not exactly. Say you have a class Farm
and inside Farm
there is horse
property.
class Farm {
let horse = Horse()
}
In this case horse
property is initialized when class instance initialized. If you make it lazy
you have to make it mutable too.
class Farm {
lazy var horse = Horse()
}
In this case, horse
property is initialized when it is accessed the first time. And later when it is accessed again it returns the same instance again instead of reinitializing it. But since it is a mutable property you can assign a new instance of Horse
to it. After you assign it new value it will return this new value whenever it is accessed.
EDIT: If let horse = Horse()
is defined in global space then it is lazily created at first access.
Swift: why aren't all variables lazy by default?
One reason might be that lazyness is not well-suited for situations where you want control when the evaluation happens. this is relevant in cases where the work being done in the assignment has side effects.
Although this pertains to closure, this blog post by stuart sierra explains this idea very well, and I think it applies equally in any language.
Swift static property initilizers are lazy why I could declared it as a constant
Neuburg M. is drawing a distinction between static properties and instance properties. You are pretending to ignore that distinction. But you cannot ignore it; they are totally different things, used for different purposes.
In this code:
class Person { // let's declare a static property
static let firstNaID = "First Name"
}
... firstNaID
is already lazy. But now try to do this:
class Person { // let's declare an instance property
lazy let firstNaID : String = "First Name" // error
}
You can't; as things stand (up thru Swift 3.1), you have to say lazy var
instead — and when you do, you get a lazy instance property.
Your static let
declaration thus doesn't accomplish what lazy let
wanted to accomplish, because a static property is not an instance property.
If global properties are always computed lazily, and local properties are never, what does the lazy modifier modify?
"Local constants and variables" in that provided excerpt refer to local scope constants and variables, as in local variables of a function. They do not refer to properties of objects, which can be lazy, if they are marked with the lazy keyword.
//global, declared outside of a class/struct
//error is "Lazy is only valid for members of a struct or class
lazy var label: UILabel = {
var tempLabel: UILabel = UILabel()
tempLabel.text = "hi"
return tempLabel
}()
class SomeClass : NSObject {
//non-lazy instance property
var x = 3
//lazy instance property
lazy var label: UILabel = {
var tempLabel: UILabel = UILabel()
tempLabel.text = "hi"
return tempLabel
}()
func doStuff() {
//error is "Lazy is only valid for members of a struct or class
lazy var label: UILabel = {
var tempLabel: UILabel = UILabel()
tempLabel.text = "hi"
return tempLabel
}()
}
}
Lazy Initialization sounds and works great. Why not always default to using lazy initialization?
Consider this example of a lazy var
:
struct S {
lazy var lazyVar: Int = { /* compute some value */ 0 }()
}
What really happens behind the scenes is something like this:
struct S {
var _lazyVar: Int? = nil
var lazyVar: Int {
mutating get {
if let existingValue = _lazyVar {
return existingValue
}
else {
let newlyComputedValue = /* compute some value */ 0
_lazyVar = newlyComputedValue
return newlyComputedValue
}
}
}
}
As you see, every access of lazyVar
requires a branch, to check if there's a value already, or if it's necessary to compute one for the first time. This adds overhead that easily outweighs the benefit of lazily evaluating values with simple (fast) derivations.
Implicitly lazy static members in Swift
The static
property defines a "type property", one that is instantiated once and only once. As you note, this happens lazily, as statics behave like globals. And as The Swift Programming Language: Properties says:
Global constants and variables are always computed lazily, in a similar manner to Lazy Stored Properties. Unlike lazy stored properties, global constants and variables do not need to be marked with the
lazy
modifier.
This implicitly lazy behavior is because, as the Swift Blog: Files and Initialization says:
it allows custom initializers, startup time in Swift scales cleanly with no global initializers to slow it down, and the order of execution is completely predictable.
They consciously designed it that way to avoid unnecessarily delaying the startup of the app.
If you want to instantiate the static
property at some particular point in your app (rather than deferring it to where it's first used), simply reference this static
property at that earlier point and the object will be initialized at that time. Given the efforts we put into reducing the latency in starting our apps, you generally wouldn't to want this synchronously during the initial launch of the app, but you can do it wherever you want.
Note that unlike lazy
instance properties, the instantiating of globals and static
variables is thread-safe.
Lazy Var vs Let
This is the latest scripture from the Xcode 6.3 Beta / Swift 1.2 release notes:
let constants have been generalized to no longer require immediate
initialization. The new rule is that a let constant must be
initialized before use (like a var), and that it may only be
initialized: not reassigned or mutated after initialization.This enables patterns like:
let x: SomeThing
if condition {
x = foo()
} else {
x = bar()
}
use(x)
which formerly required the use of a var, even though there is no
mutation taking place. (16181314)
Evidently you were not the only person frustrated by this.
Related Topics
File Couldn't Be Opened Because You Don't Have Permission to View It Error
Swift Struct with Lazy, Private Property Conforming to Protocol
How to Switch to Swift 4.0 in Xcode 9.3
How to 'Addtarget' to Uilabel in Swift
Codable Enum with Multiple Keys and Associated Values
Mandatory Init Override in Swift Uinavigationcontroller Subclass
Counting Coloured Pixels on the Gpu - Theory
Integrate Existing Aws Cognito User Pool into iOS Project with Amplify
How to Set Priority on Constraints in Swift
Mfmailcomposeviewcontroller Error [Mc] Filtering Mail Sheet Accounts for Bundle Id
Background Upload with Share Extension
Set Uitextfield Placeholder Color Programmatically
Is There an Kotlin Equivalent 'With' Function in Swift
Attrackingmanager Stopped Working in iOS 15
Type of Expression Is Ambiguous Without More Context in Xcode 11
Best Way to Structure My Firebase Database