[swift-evolution] lazy keyword vs lazy initialization pattern

Cameron Knight camjknight at mac.com
Fri Dec 4 18:33:30 CST 2015


Unless I'm missing something, this should give you the results you are looking for:

class MyClass {
    var foreignKey: Int64 {
        didSet {
            self.foreignObject = nil
        }
    }

    lazy var foreignObject: ForeignClass! = {
        return Database.expensiveSelect(self.foreignKey)
    }()
}

Using an Implicitly Unwrapped Optional instead of an Optional allows you to set foreignObject to nil which will give you the same behavior you use in Objective-C (a.k.a. null_resettable).

> To me this actually feels more like something that might fit better as an additional type of optional, rather than a language feature.
> 
> Setting this optional to nil could work normally, and any attempt to access the value when nil would cause the reload to occur. The initialization semantics might be a tad ugly though.
> 
> var myLazyOpt = ReloadingOptional<ForeignClass>({
> return Database.expensiveSelect(self.foreignKey)
> })
> 
> You could probably implement something like this yourself, though I'm not sure how elegant that would be without full language support.
> 
> Thanks for your time,
> Cole Kurkowski
> > On Dec 4, 2015, at 07:40, David Hart <david at hartbit.com <https://lists.swift.org/mailman/listinfo/swift-evolution>> 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:
> > 
> > @interface MyClass : NSObject
> > 
> > @property (nonatomic) ForeignClass* foreignObject;
> > @property (nonatomic) int64_t foreignKey;
> > 
> > @end
> > 
> > @implementation MyClass
> > 
> > - (void)setForeignKey:(int64_t)foreignKey {
> >   _foreignKey = foreignKey;
> >   _foreignObject = nil;
> > }
> > 
> > - (ForeignClass*)foreignObject {
> >   if (!_foreignObject) {
> >       _foreignObject = [Database expensiveSelect:_foreignKey];
> >   }
> >   return _foreignObject;
> > }
> > 
> > @end
> > 
> > Unfortunately, the lazy keyword in Swift, which was supposed to make the lazy initialization pattern more concsive does not work in this case:
> > 
> > class MyClass {
> >   var foreignKey: Int64 {
> >       didSet {
> >           self.foreignObject = nil
> >       }
> >   }
> > 
> >   lazy var foreignObject: ForeignClass? = {
> >       return Database.expensiveSelect(self.foreignKey)
> >   }()
> > }
> > 
> > I'm forced to rewrite it this way:
> > 
> > class MyClass {
> >   var foreignKey: Int64 {
> >       didSet {
> >           self.foreignObject = nil
> >       }
> >   }
> > 
> >   private var _foreignObject: ForeignClass? = nil
> >   var foreignObject: ForeignClass? {
> >       if _foreignObject == nil {
> >           _foreignObject = Database.expensiveSelect(self.foreignKey)
> >       }
> >       return _foreignObject
> >   }
> > }
> > 
> > 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.
> > _______________________________________________
> > swift-evolution mailing list
> > swift-evolution at swift.org <https://lists.swift.org/mailman/listinfo/swift-evolution>
> > https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151204/f354edb3/attachment.html>


More information about the swift-evolution mailing list