[swift-evolution] lazy keyword vs lazy initialization pattern
clattner at apple.com
Sun Dec 6 01:27:20 CST 2015
> On Dec 4, 2015, at 5:40 AM, David Hart <david at hartbit.com> wrote:
> In Objective-C, I often used the lazy initialization pattern to implement a cache for expensive operations. For exemple, here is an often used scenario in a project where objects behind foreign keys in a database ORM are only fetched when necessary:
> When thinking about it, I came to the conclusion that the use cases of lazy seem very narrow compared to how useful the lazy initialization pattern was in Objective-C.
> I want your opinion on three alternatives:
> 1- Do nothing, and use the slightly uglier Swift example when using a cache.
> 2- Modify lazy semantics to re-calculates when nil (I think this is the worst solution).
> 3- Add a cache modifier that re-calcualtes when nil.
My preference is:
4) Kick lazy out of the compiler and make it a standard library feature instead, allowing it to be extended in lots of ways.
The existing lazy behavior was added as a very narrow solution to a common scenario that would otherwise required optional machinations everywhere. It succeeded in that goal, but it is super narrow, and the implementation has a number of bugs (e.g. you can’t have a lazy local variable).
In terms of its narrowness, it has the limitations you describe, but it also doesn’t solve other common problems. For example, many people complain about properties that are initialized only in a second phase of initialization (e.g. awakeFromNib) and right now, most folks resort to using typing their properties as ImplicitlyUnwrappedOptional to avoid using ! at every use site. A natural solution to that is to introduce a concept of a “delayed var x : T” which does not need initialization in init(), and runtime traps if it is read before initialized. This provides similar semantics to T!, but without infecting the type system. Better than T!, a “delayed let x : T” would allow exactly one runtime initialization of the property.
The problem with this line of thinking is that - if we kept going down this path - we’d end up adding a ton of very narrow solutions for specific problems, adding language complexity all the way. This is pretty dissatisfying for a number of reasons. :-)
A different approach is to introduce a single language feature that would allow you to define customization behavior for properties in a library, which would be a general solution to these sorts of issues. Joe Groff is working on a proposal to do just this, similar to the idea of Kotlin property delegates (https://kotlinlang.org/docs/reference/delegated-properties.html).
We’ve been a bit busy lately :-) but I’m hoping that he’ll send this proposal out in the next few weeks. Assuming that proposal works out, I expect lazy to get ripped out of the language, and *that* discussion can reopen detailed debate about what the replacement should look like.
More information about the swift-evolution