[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