[swift-evolution] [Review] SE-0030 Property Behaviors

Taras Zakharko taras.zakharko at uzh.ch
Mon Feb 22 12:04:17 CST 2016


I waned to write only a quick note, but in the end it became to verbose, so I will reiterate main points here for clarity, and point to the bottom of this mail for my original messy text with more details

1. I believe that property behaviors should support static data storage. This data storage exists per declared property (as opposed for per host instance for normal storage). This has clear use cases: space data storage using weak tables etc. 

2. The magic status of ‘initialValue’ can be resolved by introducing a per-declaration initialiser that captures the initialisation expression in a static (per-property) closure. This way, everything stays explicit, there is no per-instance overhead and also no magic. However, it is questionable whether this would actually be useful in practice. 

3. Should ‘initialValue’ remain ‘magical’, I’d prefer if it had similar treatment to other compiler directives. We already have #line etc, so why not also #initialValue? That will make it clear that compiler is inserting something for you. 

> On 20 Feb 2016, at 07:16, Brent Royal-Gordon via swift-evolution <swift-evolution at swift.org> wrote:
> 
> In particular, note the point about runtime overhead. Behaviors are carefully designed to be basically equivalent to writing the same code yourself every time you need that semantic. If we weren't aiming for that, the design would be much simpler: we'd have an `init(initialValue:)` that could handle deferred initialization by using an `@autoclosure` and storing it in a property, for instance. But compared to writing the same thing yourself, that would waste memory on an extra property to store the closure, so we don't want to do that.

Just a quick note about this: I think the overhead can be avoided if the closure is stored once per property declaration rather then per object instance. This is how Python does it, for instance: properties are simply objects that define two magic methods for getting and setting values on the instance. The property object itself is instantiated only once and stored as part of the class attribute list. I can imagine that something like this could be done for Swift property behavior as well. E.g.

var behavior lazy<Value>:Value {
  var value: Value? = nil
  static let initialValue: ()->Value  

  // executed once per property declaration
  static declare(@autoclosure initialiser: ()->Value) { 
    // can only access static variables here
    initialValue = initialiser
  }

  // optional, executed once per property host instantiation
 init() {
 }
}

In a way, Joe’s proposal already does this, albeit implicitly. A refinement to make this more explicit removes the magic and gives the programmer more control.  

The question of course whether this mechanism will be useful at all, that is, whether everyone would just use the same boilerplate to capture their initialValues or whether that is some legitimate use case for this. I do not know :) If it is deemed that this is not useful, then I’d prefer if initialValue were a ‘magic’ compiler directive, e.g. #initialValue to mirror its similar status to #file and friends. 

Nevertheless, I think that static properties should be allowed for behaviors. That could enable some very powerful features, e.g. using weak dictionaries for sparse data allocation or enumeration of all objects that have particular features). 



More information about the swift-evolution mailing list