13

In comparing these two options for defining an instance property:

var networkManager = NetworkManager.sharedInstance()

var lazy networkManager = NetworkManager.sharedInstance()

Both:

  • Can evaluate a block to get the value
  • Can be declared inline (not a block, like above)

Lazy:

  • Can refer to self
  • Is not calculated until needed
  • If you don't use it, it is never calculated

Non-lazy:

  • No benefits whatsoever

It appears that there is no benefit to ever use a non-lazy variable. So why does the language allow the programmer to make this inferior choice?

(I am NOT asking about the difference between var and let à la Are Swift constants lazy by default?)

Community
  • 1
  • 1
William Entriken
  • 37,208
  • 23
  • 149
  • 195
  • 6
    Frankly, *lazy* initialization is to be avoided. It introduces non-deterministic behavior in the application and is a source of never-ending debugging adventures. It also makes refactoring much more difficult in that every change runs the risk of causing unforeseen changes because of unexpected behavior changes. – bbum Jan 17 '16 at 18:36
  • 1
    @FullDecent "class property" is not the right term and there is no such a thing in Swift (at the moment of speaking). There are instance properties and type properties... – Whirlwind Jan 17 '16 at 18:44
  • 1
    Addition to upper comments: It should be optional, because you do not want to see some performance impacts, because of allocating memory at the time your subroutine starts. Mostly, speed is too important. And in terms of debugging it would be a pain in the ass if it was default. – st. Jan 17 '16 at 19:10
  • @Whirlwind thank you updated – William Entriken Jan 18 '16 at 01:35
  • FYI. My feeling is that Swift wants to become more like a functional language and would like lazy instantiation in more places. – William Entriken Jan 18 '16 at 01:45
  • What do you mean by "Can refer to self"? – funct7 Jan 21 '16 at 07:34
  • 1
    Also this might be a reason: `If a property marked with the lazy modifier is accessed by multiple threads simultaneously and the property has not yet been initialized, there is no guarantee that the property will be initialized only once.` – funct7 Jan 21 '16 at 07:37

4 Answers4

9

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.

Sohil R. Memon
  • 9,404
  • 1
  • 31
  • 57
leeor
  • 17,041
  • 6
  • 34
  • 60
7

As others already said, there are several critical scenarios where you want the initialization of the properties to be deterministic.

This is an example (among many others) related to game development.

Often the instances of classes representing items in a game scene/level, are created before the level does begin.

Initialisation can be a time expensive task (load stuff from persistent storage, allocate memory, prepare the instances...) and doing this part before the player does begin playing the level does avoid CPU overhead.

This is critical because a CPU overhead in the middle of a level could cause a drop in the frame rate which is a nightmare for the user experience.

Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
5

FYI. My feeling is that Swift wants to become more like a functional language and would like lazy instantiation in more places.

My early assessment of Swift has held up pretty well over time (well, the "not functional" part. I didn't anticipate how much Swift would favor methods over functions in later versions). Swift is not a functional language and does not intend to be one. This has come up often in WWDC talks, on the forums, on Twitter, and in conversations with the Swift team. Originally all maps and filters were lazy. Swift removed that because of the problems it caused. Probably the best talk on that subject is "Building Better Apps with Value Types in Swift". As they say:

We like mutation. We think it's valuable. We think it's easy to use when done correctly.

You don't get much more "non-functional" than that. Swift also embraces immutable data. But functional programming is about pure functions over immutable data, and that's not Swift.

(Of course there are plenty of non-lazy functional languages. Lazy and functional are orthogonal concepts. Haskell just happened to embrace both.)

To the question at hand, though:

I've found the lazy attribute rarely useful in real-world Swift (I'm being generous; I have never encountered a case where I kept it in the code). It doesn't offer anything like the laziness you get in Haskell. It isn't thread safe, so that's a nightmare. It forces you into reference types (or forces your structs to be mutable), so that can be annoying. If I heard they were pulling it from the language and we just had to roll our own, that'd be fine with me. (I'm tempted to write a proposal to do just that.) It implements a specific memo pattern that can occasionally be handy, but often isn't the one you want. So it's a very good thing that it isn't the default.

As you likely know, global variables and class variables are lazy by default, and I think that tends to work out pretty well since there are so many fewer of them, there's a much better chance they won't be accessed in practice, and that laziness is thread safe (which has a cost, but since they're so much rarer, the cost is much lower).

Community
  • 1
  • 1
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Thanks for the discussion, and the blog is great. Now I'm a subscriber. FYI, I am using it in a reference type: `class networkManager { private let baseURL = "..."; private lazy var sessionManager: AFHTTPSessionManager = { let retval = AFHTTPSessionManager(baseURL: NSURL(string: self.SERVER_ECHO_API_URL)) ... }` – William Entriken Jan 18 '16 at 04:37
0

If you have an expensive object (in terms of, takes long to create) you would like to decide and control when it is created. One could argue that the lazy variable should be the default though. Maybe it has historical reasons. Lazy properties in ObjC resulted in a lot boilerplate code.

dasdom
  • 13,975
  • 2
  • 47
  • 58