[swift-evolution] lazy keyword vs lazy initialization pattern

Thorsten Seitz thorsten.seitz at web.de
Sun Dec 6 06:32:34 CST 2015


Hi all,

I like the property delegates feature from Kotlin, too, but I don’t see how it can replace the „delayed let x : T“ idea with initialization taking place in e.g. awakeFromNib, because a let-property cannot be set. With a var it would probably look roughly like follows, but with „let x : T by Delayed()“ the setValue method would not be allowed (at least in Kotlin):

var x : T by Delayed()

with

class Delayed<T> {
	var value : T!
	func getValue(this: Any?, property: Property<T>) -> T { return value }
	func setValue(this: Any?, property: Property<T>, value: T) {
		guard x == nil else { abort(„Property \(property) of \(this) has already been initialized when trying to initialize with value \(value)“) }
		self.value = value
	}
}

Some remarks
* I chose abort() in this particular case instead of throwing because repeated initialization should be a logical error
* Are there uses cases where throwing would be the right thing in getValue or setValue? I guess not, just like throwing is not possible in a computed property.
* Is the compiler able to optimize away the overhead of going through getValue on each access?
* I was a bit surprised that Kotlin does not require an interface for the delegates to implement. I would expect delegates to be required to implement appropriate interfaces (or protocols) like PropertyReader/PropertyAccessor, probably with a type parameter for the property owner as well (instead of Any?). The latter would allow 

-Thorsten

> Am 06.12.2015 um 11:00 schrieb David Hart via swift-evolution <swift-evolution at swift.org>:
> 
> This property delegates feature from Kotlin sounds fantastic! As the examples in Kotlin show, it could bring a very powerful solution to many problems in Swift right now: lazy being narrow, cache missing, native KVO :D
> 
> This has just become my #1 feature proposal!
> 
> Super excited David!
> 
>> On 06 Dec 2015, at 08:27, Chris Lattner <clattner at apple.com> wrote:
>> 
>> 
>>> 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.
>> 
>> Hi David,
>> 
>> 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.
>> 
>> -Chris
>> 
>> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution



More information about the swift-evolution mailing list