<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Apr 6, 2016, at 2:07 PM, Michael Peternell via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="">Hi all,<br class=""><br class="">lazy vars are not threadsafe in Swift 2. I saw code that uses lazy initialization in an unsafe way that introduces race conditions so often that I would be rich by now if get a penny each time. Many people use patterns like { if(_var == nil) { _var = [self _calculateVar]; } return _var; } or they just dispatch_once, but forget that they are in an instance method, and that it will all break if there is ever more than one instance of that class.<br class=""><br class="">I propose to make lazy vars atomic. Optionally, the old lazy var behavior could be renamed to something like lazy_nonatomic.<br class=""><br class="">I want to list some pros and cons for making lazy vars threadsafe:<br class=""><br class="">Pros:<br class="">- This proposal will not change the behavior of programs which are free from data races. I could argue that the change is therefore backwards-compatible.<br class="">- I would say that programs which require lazy vars to be nonatomic in order to function correctly, are really bad style; threadsafe lazy vars behave much more deterministic. Many programs which use lazy vars incorrectly could suddenly become safe if this proposal is implemented.<br class="">- The overhead would be minimal. For example, suppose we have a lazy var of type `NSImage`. We could represent that variable as a simple pointer which is initialized to NULL. The access could look something like this (this is just an example, there may be even more efficient solutions): {<br class=""> // we need to make sure that reads on _var are not cached:<br class=""> memory_read_barrier(&_var);<br class=""> // ^^and I'm not 100% sure that we really need that memory barrier.<br class=""> // (at least it's not needed for static vars, as proven by the implementation of dispatch_once())<br class=""><br class=""> if(_var == nil) {<br class=""> @synchronized(&_var) {<br class=""> // ^^we synchronize on &_var, and not on _var<br class=""> // this is semantically invalid in objc, but the objc-runtime supports it.<br class=""> // The point I want to make is that we don't need extra storage for the<br class=""> // synchronization, in many cases.<br class=""> if(_var != nil) {<br class=""> return _var;<br class=""> }<br class=""> ... some code that initializes _var<br class=""> }<br class=""> //@synchronized() already employs memory barriers, so no additional barriers are needed<br class=""> //maybe we should use a non-recursive lock though..<br class=""> }<br class=""> return _var;<br class="">}<br class="">- Currently, if you need threadsafety, you cannot use lazy. You can of course wrap a lock around a nonatomic lazy var, but that would be much more inefficient than a native implementation.<br class="">- I guess, no one will really complain if lazy var's are suddenly threadsafe. I also cannot see how it would break any code (except for contrived examples.)<br class="">- In some cases, the nonatomic behavior can be used as an optimization, if it is semantically equivalent. For example, a lazy var that lives in automatic storage (i.e. not an ivar or static var, but just a local var) and that is *not* captured in a closure expression can be safely initialized in a non-threadsafe way, because the variable can not be accessed from more than one thread concurrently anyways.<br class=""><br class="">Cons:<br class="">- This would be the first concurrency primitive built into the language (at least as far as I know)<br class="">- It may suggest to users of the language that other primitives (like var's) would be threadsafe too, which is obviously not the case.<br class="">- There is at least *some* runtime overhead involved. It's not zero-cost. On the other hand, lazy initialization should only be used when the cost of initialization is much higher than the cost of creating and maintaining a thunk. And in that case, I think the performance characteristics are pretty well.<br class="">- It may be out of scope for Swift 3 :-(<br class=""><br class="">Proposed solution:<br class=""><br class=""> public lazy var foo: Type = fn()<br class=""><br class="">is semantically equivalent to<br class=""><br class=""> private var _lazy_storage_foo: Type?<br class=""> private var _lazy_lock_foo: Lock<br class=""> public var foo: Type {<br class=""> get {<br class=""> var result: Type?<br class=""> _lazy_lock_foo.withLock {<br class=""> if(_lazy_storage_foo == nil) {<br class=""> _lazy_storage_foo = fn()<br class=""> }<br class=""> }<br class=""> return _lazy_storage_foo!<br class=""> }<br class=""> }<br class=""><br class="">except that the builtin solution is much more efficient, and that the two private extra vars are not exposed when you use the lazy keyword.<br class=""><br class="">All in all, I think that threadsafe lazy vars would be a nice feature for the language. I welcome feedback and am interested in a discussion.<br class=""></div></div></blockquote></div><div class=""><br class=""></div>These are good points. I think we need both nonatomic and atomic lazy variables. The syntax and scaffolding will likely fall out of Property Behaviors:<br class=""><div class=""><a href="https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md" class="">https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md</a></div><div class=""><br class=""></div><div class="">All that’s left would be optimizing the implementation, which would be premature to discuss.</div><div class=""><br class=""></div><div class="">-Andy</div></body></html>