[swift-evolution] SE-0030 Property Behaviors

Taras Zakharko taras.zakharko at uzh.ch
Sun Feb 14 01:10:22 CST 2016


Ok, fair enough. Then here a few ideas how to fix it and still stay in-line with Anton’s proposal (that i still consider much more attractive):

1. Allow behaviours to specify abstract members that need to be implemented (akin to protocols) and get the initial value of lazy from there, e.g.:

    var lazy x : T {
	func load() {
		return 33
	}
    }

  Pros: clean and clear. Cons: verbosity.

2. Allow behaviours to have members stored per property declaration and not per property instance. These members are tied to the type-level storage of the host item (e.g. class and not instance). A closure that initialises the lazy storage can be stored at that level, thus solving the storage overhead issue. One can use the static declarations for this (although a new storage class might be appropriate). Note that Python uses this kind of approach per default: instances of property descriptors are created per class that hosts a property and not per instance. The property getter/setter then receives the specific object instance to manipulate the value specific to that instance. 

 Pros: clean and clear. Cons: potentially need new storage declaration.

— Taras 


> On 12 Feb 2016, at 22:59, Joe Groff <jgroff at apple.com> wrote:
> 
> 
>> On Feb 12, 2016, at 1:45 PM, Taras Zakharko <taras.zakharko at uzh.ch <mailto:taras.zakharko at uzh.ch>> wrote:
>> 
>> I like Anton’s proposal much better! Clean, obvious and down to the point. 
>> 
>>> On 12 Feb 2016, at 21:44, Joe Groff via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> 
>>> IMO it's unacceptable to have to store a closure for every individual lazy property. That significantly increases the storage cost of the abstraction.
>>> 
>>> -Joe
>> 
>> Maybe I am missing something obvious here but what would be a practical example of a lazy variable that does not rely on a closure to provide the initial value? Besides, storing an additional pointer per property is what, 8 bytes overhead? Barely worth mentioning. And of course, if you want to be very efficient about it you can always use a global hash map to store the closures. 
> 
> A Swift closure is two pointers wide—a function pointer, and a context pointer. The per-instance overhead for Optional<T> will already cost a word for many types without an extra bit or representation for 'None'.
> 
>> BTW, the lazy implementation you propose also has additional overhead, but its hidden (initialValue needs to be stored somewhere before the first call to get). In fact, your solution might be even worse in terms of storage overhead, because it implies that individual closure with unique environment needs to be created for getters of every instance of the property with different initialiser. 
> 
> As currently implemented, 'lazy' inlines the initializer expression into the property's getter implementation, so the only overhead is some code size in the getter function. A behavior implementation of [lazy] needs to afford the same opportunity to the optimizer. One way we could model this is as 'static' members in the behavior, perhaps.
> 
> -Joe

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


More information about the swift-evolution mailing list