[swift-evolution] [Proposal] Property behaviors

Joe Groff jgroff at apple.com
Sat Jan 16 13:18:17 CST 2016


> On Jan 16, 2016, at 4:39 AM, Tino Heth <2th at gmx.de> wrote:
> 
> I'm always in favor of removing special cases (like lazy and willSet/didSet), so the idea of property behaviors itself is very appealing to me.
> There's one downside, though:
> The proposal makes some keywords obsolete, but introduces a whole bunch of new stuff in exchange — and all of this only can be used with properties…
> 
> I hope you agree with me that there is merit in keeping the language small (it's called "Swift", not "Turkey" ;-), and that the proposal would improve if it's possible to slim it down.
> 
> Imho the first step to add property behaviors should be refining how properties are modeled in Swift:
> In many languages, properties are represented as a pair of methods (setter and getter), and their absence has several downsides (functional programming works best with functions ;-).
> 
> As soon as there is a way to read and write properties in a functional way, their behaviors could be expressed in a universal manner:
> Afaics, all major use cases for behaviors can be implemented as simple "decorators" — in fact, I could simulate most examples from the proposal in a tiny playground (a part of it is attached).
> Of course, the simulation is ugly, but I am confident that some nice ideas would come up if properties were more accessible.

Believe me, I would prefer to keep the language impact small too. There are a couple of issues that make this difficult with property behaviors:

- First of all, Swift properties are *not* a simple getter-setter pair. Get and set is an inefficient protocol for value types, since any mutation of part of a value through get/set requires copying the entire value by 'get', mutating the temporary copy, then copying the entire modified value back by 'set'. If properties were limited to a get/set interface, every partial update of an array 'foo.arrayProperty[0] = 1' would force at minimum one full copy of the array buffer. It's better to think of a property as a mutable projection function, `inout T -> inout U`, and in fact I plan to propose allowing 'inout' returns as a way of abstracting over properties and other projections.

- If we had inout-projecting functions, it's true that the property implementation part of most behaviors could be modeled as functional transformations, e.g.:

// Turn an optional property into a 'lazy' non-optional property
func lazy<Container, Value>(@autoclosure initialValue initialValue: () -> Value, property: inout Value?) -> inout Value {
  func adapter() -> inout Value
    get {
      if let value = property() { return value }
      let initial = initialValue()
      property() = initial
      return initial
    }
    set {
      property() = newValue
    }
  }
  return adapter
}

However, there's more to a behavior than the property implementation itself. We also want behaviors to be able to encapsulate the backing storage for their properties, including their initialization. The compiler could perhaps infer backward from the signature of `lazy` above that, in order to produce a lazy property of type `Value`, it needs to back it with a property of type `Value?`, but it still doesn't know how or when `lazy` expects that storage to be initialized. Furthermore, we want behaviors to be able to attach behavior-specific operations to their properties, such as to clear a lazy property or reset a property to a private default value. While both of these issues can be addressed by explicitly exposing the backing storage as a separate property:

var fooStorage: Int? = nil
var foo: Int { return &lazy(initialValue: 1738, property: &fooStorage) }

that's quite a bit of boilerplate, and it also clutters the user interface for the type, since the storage now appears as a separate entity from the property itself. We want behaviors to be lightweight and easy to use, and on balance I think the best way to deliver that is with some specialized functionality.

-Joe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160116/5b09356c/attachment.html>


More information about the swift-evolution mailing list