[swift-evolution] lazy keyword vs lazy initialization pattern
David Hart
david at hartbit.com
Fri Dec 4 07:40:39 CST 2015
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.
More information about the swift-evolution
mailing list