<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">I’ve really been looking forward to this proposal and I like this idea in general. &nbsp;I may have comments about specific details after giving it more thought.<div class=""><br class=""></div><div class="">I have one significant concern that is worth mentioning immediately. &nbsp;I would consider it extremely unfortunate if a delayed property behavior was considered sufficient in support of multi-phase initialization. &nbsp;Using a property behavior for that purpose gives no guarantee that the value is actually initialized at some point during instance initialization. &nbsp;IMO this is a major flaw. &nbsp;A runtime error might occur when accessing a delayed property after initialization is supposed to be complete.</div><div class=""><br class=""></div><div class="">Delayed property behaviors may have appropriate use cases but IMO they are not an adequate substitute for something that provides stronger guarantees for the common case of multi-phase initialization.</div><div class=""><br class=""></div><div class="">I very strongly prefer to see direct language support for multi-phase initialization. &nbsp;The compiler could provide most of the initialization guarantees it does for regular let properties. &nbsp;It could enforce single assignment in the initializer body and could prevent the initializer body itself from reading the delayed property before assignment. &nbsp;</div><div class=""><br class=""></div><div class="">The only guarantee that may not be possible is method calls to self during the second phase of initialization, but prior to assignment of all delayed properties (whether directly or by passing self to another instance) are potentially dangerous if they caused a read to a delayed property. &nbsp;The potential for error is significantly narrower with direct language support. &nbsp;As this is a very common use case (possibly the most common use case for delayed properties) I strongly believe it warrants direct language support.</div><div class=""><br class=""></div><div class="">Matthew</div><div class=""><div class=""><div class=""><br class=""></div><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Dec 17, 2015, at 11:37 AM, Joe Groff via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Hi everyone. Chris stole my thunder already—yeah, I've been working on a design for allowing properties to be extended with user-defined <strike class="">delegates^W</strike> behaviors. Here's a draft proposal that I'd like to open up for broader discussion. Thanks for taking a look!<div class=""><br class=""></div><div class="">-Joe</div><div class=""><br class=""></div><div class=""><a href="https://gist.github.com/jckarter/f3d392cf183c6b2b2ac3" class="">https://gist.github.com/jckarter/f3d392cf183c6b2b2ac3</a></div><div class=""><br class=""></div><div class=""><div id="wrapper" style="font-size: 14px; font-family: helvetica, arial, freesans, clean, sans-serif; -webkit-font-smoothing: subpixel-antialiased; line-height: 1.6; padding: 30px; background-color: rgb(255, 255, 255); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; margin: 15px; box-shadow: rgb(202, 202, 202) 0px 0px 0px 1px, rgb(238, 238, 238) 0px 0px 0px 4px; outline: 0px; border: 0px;" class=""><h1 id="propertybehaviors" style="margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 28px; transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out; margin-top: 0px !important;" class="">Property Behaviors</h1><ul style="padding-left: 30px;" class=""><li class="">Proposal:&nbsp;<a href="https://github.com/apple/swift-evolution/proposals/NNNN-name.md" style="color: rgb(65, 131, 196); text-decoration: none; margin-top: 0px;" class="">SE-NNNN</a></li><li class="">Author(s):&nbsp;<a href="https://github.com/jckarter" style="color: rgb(65, 131, 196); text-decoration: none; margin-top: 0px;" class="">Joe Groff</a></li><li class="">Status:&nbsp;<strong style="margin-top: 0px;" class="">Review</strong></li><li class="">Review manager: TBD</li></ul><h2 id="introduction" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 24px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(204, 204, 204); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">Introduction</h2><p style="margin: 0px 0px 15px;" class="">There are property implementation patterns that come up repeatedly. Rather than hardcode a fixed set of patterns into the compiler, we should provide a general “property behavior” mechanism to allow these patterns to be defined as libraries.</p><h2 id="motivation" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 24px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(204, 204, 204); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">Motivation</h2><p style="margin: 0px 0px 15px;" class="">We’ve tried to accommodate several important patterns for property with targeted language support, but this support has been narrow in scope and utility. For instance, Swift 1 and 2 provide&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">lazy</code>&nbsp;properties as a primitive language feature, since lazy initialization is common and is often necessary to avoid having properties be exposed as&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">Optional</code>. Without this language support, it takes a lot of boilerplate to get the same effect:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">class Foo {
  // lazy var foo = 1738
  private var _foo: Int?
  var foo: Int {
    get {
      if let value = _foo { return value }
      let initialValue = 1738
      _foo = initialValue
      return initialValue
    }
    set {
      _foo = newValue
    }
  }
}</code></pre><p style="margin: 15px 0px;" class="">Building&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">lazy</code>&nbsp;into the language has several disadvantages. It makes the language and compiler more complex and less orthogonal. It’s also inflexible; there are many variations on lazy initialization that make sense, but we wouldn’t want to hardcode language support for all of them. For instance, some applications may want the lazy initialization to be synchronized, but&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">lazy</code>only provides single-threaded initialization. The standard implementation of&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">lazy</code>&nbsp;is also problematic for value types. A&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">lazy</code>getter must be&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">mutating</code>, which means it can’t be accessed from an immutable value. Inline storage is also suboptimal for many memoization tasks, since the cache cannot be reused across copies of the value. A value-oriented memoized property implementation might look very different:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">class MemoizationBox&lt;T&gt; {
  var value: T? = nil
  init() {}
  func getOrEvaluate(fn: () -&gt; T) -&gt; T {
    if let value = value { return value }
    // Perform initialization in a thread-safe way.
    // Implementation of `sync` not shown here
    return sync {
      let initialValue = fn()
      value = initialValue
      return initialValue
    }
  }
}

struct Person {
  let firstName: String
  let lastName: String

  let _cachedFullName = MemoizationBox&lt;String&gt;()

  var fullName: String {
    return _cachedFullName.getOrEvaluate { "\(firstName) \(lastName)" }
  }
}</code></pre><p style="margin: 15px 0px;" class="">Lazy properties are also unable to surface any additional operations over a regular property. It would be useful to be able to reset a lazy property’s storage to be recomputed again, for instance, but this isn’t possible with&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">lazy</code>.</p><p style="margin: 15px 0px;" class="">There are important property patterns outside of lazy initialization. It often makes sense to have “delayed”, once-assignable-then-immutable properties to support multi-phase initialization:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">class Foo {
  let immediatelyInitialized = "foo"
  var _initializedLater: String?

  // We want initializedLater to present like a non-optional 'let' to user code;
  // it can only be assigned once, and can't be accessed before being assigned.
  var initializedLater: String {
    get { return _initializedLater! }
    set {
      assert(_initializedLater == nil)
      _initializedLater = newValue
    }
  }
}
</code></pre><p style="margin: 15px 0px;" class="">Implicitly-unwrapped optionals allow this in a pinch, but give up a lot of safety compared to a non-optional ‘let’. Using IUO for multi-phase initialization gives up both immutability and nil-safety.</p><p style="margin: 15px 0px;" class="">We also have other application-specific property features like&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">didSet</code>/<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">willSet</code>&nbsp;and array addressors that add language complexity for limited functionality. Beyond what we’ve baked into the language already, there’s a seemingly endless set of common property behaviors, including resetting, synchronized access, and various kinds of proxying, all begging for language attention to eliminate their boilerplate.</p><h2 id="proposedsolution" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 24px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(204, 204, 204); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">Proposed solution</h2><p style="margin: 0px 0px 15px;" class="">I suggest we allow for&nbsp;<strong class="">property behaviors</strong>&nbsp;to be implemented within the language. A&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">var</code>&nbsp;or&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">let</code>&nbsp;declaration can specify its behavior in parens after the keyword:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">var (lazy) foo = 1738</code></pre><p style="margin: 15px 0px;" class="">which acts as sugar for something like this:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">var `foo.lazy` = lazy(var: Int.self, initializer: { 1738 })
var foo: Int {
  get {
    return `foo.lazy`[varIn: self,
                      initializer: { 1738 }]
  }
  set {
    `foo.lazy`[varIn: self,
               initializer: { 1738 }] = newValue
  }
}</code></pre><p style="margin: 15px 0px;" class="">Furthermore, the behavior can provide additional operations, such as&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">clear</code>-ing a lazy property, by accessing it with&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">property.behavior</code>&nbsp;syntax:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">foo.lazy.clear()</code></pre><p style="margin: 15px 0px;" class="">(The syntax for declaring and accessing the behavior is up for grabs; I’m offering these only as a starting point.)</p><p style="margin: 15px 0px;" class="">Property behaviors obviate the need for special language support for&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">lazy</code>, observers, addressors, and other special-case property behavior, letting us move their functionality into libraries and support new behaviors as well.</p><h2 id="examples" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 24px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(204, 204, 204); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">Examples</h2><p style="margin: 0px 0px 15px;" class="">Before describing the detailed design, I’ll run through some examples of potential applications for behaviors.</p><h4 id="lazy" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 16px; color: rgb(51, 51, 51); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">Lazy</h4><p style="margin: 0px 0px 15px;" class="">The current&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">lazy</code>&nbsp;property feature can be reimplemented as a property behavior:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">public struct Lazy&lt;Value&gt; {
  var value: Value?

  public init() {
    value = nil
  }

  public subscript&lt;Container&gt;(varIn _: Container,
                              initializer initial: () -&gt; Value) -&gt; Value {
    mutating get {
      if let existingValue = value {
        return existingValue
      }
      let initialValue = initial()
      value = initialValue
      return initialValue
    }
    set {
      value = newValue
    }
  }
}

public func lazy&lt;Value&gt;(var type: Value.Type, initializer _: () -&gt; Value)
    -&gt; Lazy&lt;Value&gt; {
  return Lazy()
}</code></pre><p style="margin: 15px 0px;" class="">As mentioned above,&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">lazy</code>&nbsp;in Swift 2 doesn’t provide a way to reset a lazy value to reclaim memory and let it be recomputed later. A behavior can provide additional operations on properties that use the behavior; for instance, to&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">clear</code>&nbsp;a lazy property:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">extension Lazy {
  public mutating func clear() {
    value = nil
  }
}

var (lazy) x = somethingThatEatsMemory()
use(x)
x.lazy.clear()</code></pre><h4 id="memoization" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 16px; color: rgb(51, 51, 51); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">Memoization</h4><p style="margin: 0px 0px 15px;" class="">Variations of&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">lazy</code>&nbsp;can be implemented that are more appropriate for certain situations. For instance, here’s a&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">memoized</code>behavior that stores the cached value indirectly, making it suitable for immutable value types:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">public class MemoizationBox&lt;Value&gt; {
  var value: Value? = nil
  init() {}
  func getOrEvaluate(fn: () -&gt; Value) -&gt; Value {
    if let value = value { return value }
    // Perform the initialization in a thread-safe way.
    // Implementation of 'sync' not shown here.
    return sync {
      let initialValue = fn()
      value = initialValue
      return initialValue
    }
  }
  func clear() {
    value = nil
  }

  public subscript&lt;Container&gt;(letIn _: Container,
                              initializer value: () -&gt; Value) -&gt; Value {
    return box.getOrEvaluate(value)
  }
}

public func memoized&lt;Value&gt;(let type: Value.Type, initializer: () -&gt; Value)
    -&gt; MemoizationBox&lt;Value&gt; {
  return MemoizationBox()
}
</code></pre><p style="margin: 15px 0px;" class="">Which can then be used like this:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">struct Location {
  let street, city, postalCode: String

  let (memoized) address = "\(street)\n\(city) \(postalCode)"
}</code></pre><h4 id="delayedinitialization" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 16px; color: rgb(51, 51, 51); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">Delayed Initialization</h4><p style="margin: 0px 0px 15px;" class="">A property behavior can model “delayed” initialization behavior, where the DI rules for&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">var</code>&nbsp;and&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">let</code>&nbsp;properties are enforced dynamically rather than at compile time:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">public func delayed&lt;Value&gt;(let type: Value.Type) -&gt; Delayed&lt;Value&gt; {
  return Delayed()
}
public func delayed&lt;Value&gt;(var type: Value.Type) -&gt; Delayed&lt;Value&gt; {
  return Delayed()
}

public struct Delayed&lt;Value&gt; {
  var value: Value? = nil

  /// DI rules for vars:
  /// - Must be assigned before being read
  public subscript&lt;Container&gt;(varIn container: Container) {
    get {
      if let value = value {
        return value
      }
      fatalError("delayed var used before being initialized")
    }
    set {
      value = newValue
    }
  }

  /// DI rules for lets:
  /// - Must be initialized once before being read
  /// - Cannot be reassigned
  public subscript&lt;Container&gt;(letIn container: Container) {
    get {
      if let value = value {
        return value
      }
      fatalError("delayed let used before being initialized")
    }
  }

  /// Behavior operation to initialize a delayed variable
  /// or constant.
  public mutating func initialize(value: Value) {
    if let value = value {
      fatalError("delayed property already initialized")
    }
    self.value = value
  }
}</code></pre><p style="margin: 15px 0px;" class="">which can be used like this:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">class Foo {
  let (delayed) x: Int

  init() {
    // We don't know "x" yet, and we don't have to set it
  }

  func initializeX(x: Int) {
    self.x.delayed.initialize(x) // Will crash if 'self.x' is already initialized
  }

  func getX() -&gt; Int {
    return x // Will crash if 'self.x' wasn't initialized
  }
}</code></pre><h4 id="resettableproperties" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 16px; color: rgb(51, 51, 51); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">Resettable properties</h4><p style="margin: 0px 0px 15px;" class="">There’s a common pattern in Cocoa where properties are used as optional customization points, but can be reset to nil to fall back to a non-public default value. In Swift, properties that follow this pattern currently must be imported as ImplicitlyUnwrappedOptional, even though the property can only be&nbsp;<em class="">set</em>&nbsp;to nil. If expressed as a behavior, the&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">reset</code>&nbsp;operation can be decoupled from the type, allowing the property to be exported as non-optional:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">public func resettable&lt;Value&gt;(var type: Value.Type,
                      initializer fallback: () -&gt; Value) -&gt; Resettable&lt;Value&gt; {
  return Resettable(value: fallback())
}
public struct Resettable&lt;Value&gt; {
  var value: Value?

  public subscript&lt;Container&gt;(varIn container: Container,
                              initializer fallback: () -&gt; Value) -&gt; Value {
    get {
      if let value = value { return value }
      return fallback()
    }
    set {
      value = newValue
    }
  }

  public mutating func reset() {
    value = nil
  }
}

var (resettable) foo: Int = 22
print(foo) // =&gt; 22
foo = 44
print(foo) // =&gt; 44
foo.resettable.reset()
print(foo) // =&gt; 22</code></pre><h4 id="synchronizedpropertyaccess" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 16px; color: rgb(51, 51, 51); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">Synchronized Property Access</h4><p style="margin: 0px 0px 15px;" class="">Objective-C supports&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">atomic</code>&nbsp;properties, which take a lock on&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">get</code>&nbsp;and&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">set</code>&nbsp;to synchronize accesses to a property. This is occasionally useful, and it can be brought to Swift as a behavior:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">// A class that owns a mutex that can be used to synchronize access to its
// properties.
//
// `NSObject` could theoretically be extended to implement this using the
// object's `@synchronized` lock.
public protocol Synchronizable: class {
  func withLock&lt;R&gt;(@noescape body: () -&gt; R) -&gt; R
}

public func synchronized&lt;Value&gt;(var _: Value.Type,
                                initializer initial: () -&gt; Value)
    -&gt; Synchronized&lt;Value&gt; {
  return Synchronized(value: initial())
}

public struct Synchronized&lt;Value&gt; {
  var value: Value

  public subscript&lt;Container: Synchronizable&gt;(varIn container: Container,
                                              initializer _: () -&gt; Value)
      -&gt; Value {
    get {
      return container.withLock {
        return value
      }
    }
    set {
      container.withLock {
        value = newValue
      }
    }
  }
}</code></pre><h4 id="nscopying" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 16px; color: rgb(51, 51, 51); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class=""><code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px;" class="">NSCopying</code></h4><p style="margin: 0px 0px 15px;" class="">Many Cocoa classes implement value-like objects that require explicit copying. Swift currently provides an&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">@NSCopying</code>&nbsp;attribute for properties to give them behavior like Objective-C’s&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">@property(copy)</code>, invoking the&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">copy</code>&nbsp;method on new objects when the property is set. We can turn this into a behavior:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">public func copying&lt;Value: NSCopying&gt;(var _: Value.Type,
                                      initializer initial: () -&gt; Value)
    -&gt; Copying&lt;Value&gt; {
  return Copying(value: initial().copy())
}

public struct Copying&lt;Value&gt; {
  var value: Value

  public subscript&lt;Container&gt;(varIn container: Container,
                              initializer _: () -&gt; Value)
      -&gt; Value {
    get {
      return value
    }
    set {
      value = newValue.copy()
    }
  }
}</code></pre><h4 id="referencingpropertieswithpointers" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 16px; color: rgb(51, 51, 51); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">Referencing Properties with Pointers</h4><p style="margin: 0px 0px 15px;" class="">We provide some affordances for interfacing properties with pointers for C interop and performance reasons, such as&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">withUnsafePointer</code>&nbsp;and implicit argument conversions. These affordances come with a lot of caveats and limitations. A property behavior can be defined that implements properties with manually-allocated memory, guaranteeing that pointers to the property can be freely taken and used:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">public func pointable&lt;Value&gt;(var _: Value.Type,
                             initializer initial: () -&gt; Value)
    -&gt; Pointable&lt;Value&gt; {
  return Pointable(value: initial())
}

public class Pointable&lt;Value&gt; {
  public let pointer: UnsafeMutablePointer&lt;Value&gt;

  init(value: Value) {
    pointer = .alloc(1)
    pointer.initialize(value)
  }

  deinit {
    pointer.destroy()
    pointer.dealloc(1)
  }

  public subscript&lt;Container&gt;(varIn _: Container,
                              initializer _: () -&gt; Value)
      -&gt; Value {
    get {
      return pointer.memory
    }
    set {
      pointer.memory = newValue
    }
  }
}

var (pointable) x = 22
var (pointable) y = 44

memcpy(x.pointable.pointer, y.pointable.pointer, sizeof(Int.self))
print(x) // =&gt; 44</code></pre><p style="margin: 15px 0px;" class="">(Manually allocating and deallocating a pointer in a&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">class</code>&nbsp;is obviously not ideal, but is shown as an example. A production-quality stdlib implementation could use compiler magic to ensure the property is stored in-line in an addressable way.)</p><h4 id="propertyobservers" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 16px; color: rgb(51, 51, 51); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">Property Observers</h4><p style="margin: 0px 0px 15px;" class="">A property behavior can also replicate the built-in behavior of&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">didSet</code>/<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">willSet</code>&nbsp;observers:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">typealias ObservingAccessor = (oldValue: Value, newValue: Value) -&gt; ()

public func observed&lt;Value&gt;(var _: Value.Type,
                            initializer initial: () -&gt; Value,
                            didSet _: ObservingAccessor = {},
                            willSet _: ObservingAccessor = {})
    -&gt; Observed&lt;Value&gt; {
  return Observed(value: initial())
}

public struct Observed&lt;Value&gt; {
  var value: Value

  public subscript&lt;Container&gt;(varIn _: Container,
                              initializer _: () -&gt; Value,
                              didSet didSet: ObservingAccessor = {},
                              willSet willSet: ObservingAccessor = {})
      -&gt; Value {
    get { return value }
    set {
      let oldValue = value
      willSet(oldValue, newValue)
      value = newValue
      didSet(oldValue, newValue)
    }
  }
}</code></pre><p style="margin: 15px 0px;" class="">A common complaint with&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">didSet</code>/<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">willSet</code>&nbsp;is that the observers fire on&nbsp;<em class="">every</em>&nbsp;write, not only ones that cause a real change. A behavior that supports a&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">didChange</code>&nbsp;accessor, which only gets invoked if the property value really changed to a value not equal to the old value, can be implemented as a new behavior:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">public func changeObserved&lt;Value: Equatable&gt;(var _: Value.Type,
                                             initializer initial: () -&gt; Value,
                                             didChange _: ObservingAccessor = {})
    -&gt; ChangeObserved&lt;Value&gt; {
  return ChangeObserved(value: initial())
}

public struct ChangeObserved&lt;Value: Equatable&gt; {
  var value: Value

  public subscript&lt;Container&gt;(varIn _: Container,
                              initializer _: () -&gt; Value,
                              didChange didChange: ObservingAccessor = {}) {
    get { return value }
    set {
      if value == newValue { return }
      value = newValue
      didChange(oldValue, newValue)
    }
  }
}</code></pre><p style="margin: 15px 0px;" class=""><b id="firstdiff" style="transition: color 0.2s ease-in-out; -webkit-transition: color 0.2s ease-in-out; position: absolute; display: block; left: 0px; border: none !important;" class=""></b>This is a small sampling of the possibilities of behaviors. Let’s look at how they can be implemented:</p><h2 id="detaileddesign" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 24px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(204, 204, 204); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">Detailed design</h2><p style="margin: 0px 0px 15px;" class="">A property declaration can declare a&nbsp;<strong class="">behavior</strong>&nbsp;after the&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">var</code>&nbsp;or&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">let</code>&nbsp;keyword in parens:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">var (runcible) foo: Int</code></pre><p style="margin: 15px 0px;" class="">(Possible alternatives to&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">var (behavior)</code>&nbsp;are discussed later.) Inside the parens is a dotted declaration reference that must refer to a&nbsp;<strong class="">behavior function</strong>&nbsp;that accepts the property attributes (such as its name, type, initial value (if any), and accessor methods) as parameters. How attributes map to parameters is discussed below.</p><p style="margin: 15px 0px;" class="">When a property declares a behavior, the compiler expands this into a&nbsp;<strong class="">backing property</strong>, which is initialized by invoking the behavior function with the property’s attributes as arguments. The backing property takes on whatever type is returned by the behavior function. The declared property forwards to the accessors of the backing property’s&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">subscript(varIn:...)</code>&nbsp;(or&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">subscript(letIn:...)</code>) member, with&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">self</code>&nbsp;as the first argument (or&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">()</code>&nbsp;for a free variable declaration). The subscript may also accept any or all of the property’s attributes as arguments. Approximately, the expansion looks like this:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">var `foo.runcible` = runcible(var: Int.self)
var foo: Int {
  return `foo.runcible`[varIn: self]
}</code></pre><p style="margin: 15px 0px;" class="">with the fine print that the property directly receives the&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">get</code>,&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">set</code>,&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">materializeForSet</code>, etc. accessors from the behavior’s subscript declaration. By forwarding to a subscript instead of separate&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">get</code>&nbsp;and&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">set</code>&nbsp;methods, property behaviors preserve all of the mutable property optimizations we support now and in the future for free. The subscript also determines the mutability of the declared property.</p><p style="margin: 15px 0px;" class="">The behavior function is resolved by building a call with the following keyword arguments, based on the property declaration:</p><ul style="padding-left: 30px;" class=""><li class="">The metatype of the declared property’s type is passed as an argument labeled&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">var</code>&nbsp;for a&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">var</code>, or labeled&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">let</code>&nbsp;for a&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">let</code>.</li><li class="">If the declared property provides an initial value, the initial value expression is passed as a&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">() -&gt; T</code>&nbsp;closure to an argument labeled&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">initializer</code>.</li><li class="">If the property is declared with accessors, their bodies are passed by named parameters corresponding to their names. Accessor names can be arbitrary identifiers.</li></ul><p style="margin: 15px 0px;" class="">For example, a property with a behavior and initial value:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">var (runcible) foo = 1738</code></pre><p style="margin: 15px 0px;" class="">gets its backing property initialized as follows:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">var `foo.runcible` = runcible(var: Int.self, initializer: { 1738 })</code></pre><p style="margin: 15px 0px;" class="">A property that declares accessor methods:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">var (runcible) foo: Int {
  bar { print("bar") }
  bas(x) { print("bas \(x)") }
}</code></pre><p style="margin: 15px 0px;" class="">passes those accessors on to its behavior function:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">private func `foo.bar`() { print("bar") }
private func `foo.bas`(x: T) { print("bar") }

var `foo.runcible` = runcible(var: Int.self,
                              bar: self.`foo.bar`,
                              bas: self.`foo.bas`)</code></pre><p style="margin: 15px 0px;" class="">Contextual types from the selected behavior function can be used to infer types for the accessors’ parameters as well as their default names. For example, if the behavior function is declared as:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">func runcible&lt;T&gt;(var type: T.Type, bar: (newValue: T) -&gt; ())
  -&gt; RuncibleProperty&lt;T&gt;</code></pre><p style="margin: 15px 0px;" class="">then a&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">bar</code>&nbsp;accessor using this behavior can implicitly receive&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">newValue</code>&nbsp;as a parameter:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">var (runcible) x: Int {
  bar { print("\(newValue.dynamicType)") } // prints Int
}</code></pre><p style="margin: 15px 0px;" class="">Once the behavior function has been resolved, its return type is searched for a matching&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">subscript</code>&nbsp;member with labeled index arguments:</p><ul style="padding-left: 30px;" class=""><li class="">The&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">self</code>&nbsp;value that contains the property is passed to a labeled&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">varIn</code>&nbsp;argument for a&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">var</code>, or a&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">letIn</code>&nbsp;argument for a&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">let</code>. This may be the metatype for a static property, or&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">()</code>&nbsp;for a global or local property.</li><li class="">After these arguments, the subscript must take the same labeled&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">initializer</code>&nbsp;and/or accessor closure arguments as the behavior function.</li></ul><p style="margin: 15px 0px;" class="">It is an error if a matching&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">subscript</code>&nbsp;can’t be found on the type. By constraining what types are allowed to be passed to the&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">varIn</code>&nbsp;or&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">letIn</code>&nbsp;parameter of the subscript, a behavior can constrain what kinds of container it is allowed to appear in.</p><p style="margin: 15px 0px;" class="">By passing the initializer and accessor bodies to both the behavior function and subscript, the backing property can avoid requiring storage for closures it doesn’t need immediately at initialization time. It would be unacceptable if every&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">lazy</code>&nbsp;property needed to store its initialization closure in-line, for instance. The tradeoff is that there is potentially redundant work done forming these closures at both initialization and access time, and many of the arguments are not needed by both. However, if the behavior function and subscript are both&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">inlineable</code>, the optimizer ought to be able to eliminate dead arguments and simplify closures. For most applications, the attribute closures ought to be able to be&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">@noescape</code>&nbsp;as well.</p><p style="margin: 15px 0px;" class="">Some behaviors may have special operations associated with them; for instance, a&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">lazy</code>&nbsp;property may provide a way to&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">clear</code>&nbsp;itself to reclaim memory and allow the value to be recomputed later when needed. The underlying backing property may be accessed by referencing it as&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">property.behavior</code>.</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">var (lazy) x = somethingThatEatsMemory()

use(x)
x.lazy.clear() // free the memory</code></pre><p style="margin: 15px 0px;" class="">The backing property has&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">internal</code>&nbsp;visibility by default (or&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">private</code>&nbsp;if the declared property is&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">private</code>). If the backing property should have higher visibility, the visibility can be declared next to the behavior:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">public var (public lazy) x = somethingThatEatsMemory()</code></pre><p style="margin: 15px 0px;" class="">However, the backing property cannot have higher visibility than the declared property.</p><p style="margin: 15px 0px;" class="">The backing property is always a stored&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">var</code>&nbsp;property. It is the responsibility of a&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">let</code>&nbsp;property behavior’s implementation to provide the expected behavior of an immutable property over it. A well behaved&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">let</code>&nbsp;should produce an identical value every time it is loaded, or die trying, as in the case of an uninitialized&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">delayed</code>&nbsp;let. A&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">let</code>&nbsp;should be safe to read concurrently from multiple threads. (In the fullness of time, an effects system might be able to enforce this, with escape hatches for internally-impure things like memoization of course.)</p><h2 id="impactonexistingcode" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 24px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(204, 204, 204); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">Impact on existing code</h2><p style="margin: 0px 0px 15px;" class="">By itself, this is an additive feature that doesn’t impact existing code. However, it potentially obsoletes&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">lazy</code>,&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">willSet</code>/<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">didSet</code>, and&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">@NSCopying</code>&nbsp;as hardcoded language features. We could grandfather these in, but my preference would be to phase them out by migrating them to library-based property behavior implementations. (Removing them should be its own separate proposal, though.)</p><p style="margin: 15px 0px;" class="">It’s also worth exploring whether property behaviors could replace the “addressor” mechanism used by the standard library to implement&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">Array</code>&nbsp;efficiently. It’d be great if the language only needed to expose the core conservative access pattern (<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">get</code>/<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">set</code>/<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">materializeForSet</code>) and let all variations be implemented as library features. Note that superseding&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">didSet</code>/<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">willSet</code>&nbsp;and addressors completely would require being able to apply behaviors to subscripts in addition to properties, which seems like a reasonable generalization.</p><h2 id="alternativesconsideredtoconsider" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 24px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(204, 204, 204); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">Alternatives considered/to consider</h2><h3 id="declarationsyntax" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 18px; color: rgb(51, 51, 51); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">Declaration syntax</h3><p style="margin: 0px 0px 15px;" class="">Alternatives to the proposed&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">var (behavior) propertyName</code>&nbsp;syntax include:</p><ul style="padding-left: 30px;" class=""><li class="">An attribute, such as&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">@behavior(lazy)</code>&nbsp;or&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">behavior(lazy) var</code>. This is the most conservative answer, but is clunky.</li><li class="">Use the behavior function name directly as an attribute, so that e.g.&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">@lazy</code>&nbsp;works. This injects functions into the attribute namespace, which is problematic (but maybe not as much if the function itself also has to be marked with a&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">@behavior_function</code>&nbsp;attribute too).</li><li class="">Use a new keyword, as in&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">var x: T by behavior</code>.</li><li class="">Something on the right side of the colon, such as&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">var x: lazy(T)</code>. To me this reads like&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">lazy(T)</code>&nbsp;is a type of some kind, which it really isn’t.</li><li class="">Something following the property name, such as&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">var x«lazy»: T</code>&nbsp;or&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">var x¶lazy: T</code>&nbsp;(picking your favorite ASCII characters to replace&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">«»¶</code>). One nice thing about this approach is that it suggests&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">self.x«lazy»</code>&nbsp;as a declaration-follows-use way of accessing the backing property.</li></ul><h3 id="syntaxforaccessingthebackingproperty" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 18px; color: rgb(51, 51, 51); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">Syntax for accessing the backing property</h3><p style="margin: 0px 0px 15px;" class="">The proposal suggests&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">x.behaviorName</code>&nbsp;for accessing the underlying backing property of&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">var (behaviorName) x</code>. The main disadvantage of this is that it complicates name lookup, which must be aware of the behavior in order to resolve the name, and is potentially ambiguous, since the behavior name could of course also be the name of a member of the property’s type. Some alternatives to consider:</p><ul style="padding-left: 30px;" class=""><li class="">Reserving a keyword and syntactic form to refer to the backing property, such as&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">foo.x.behavior</code>&nbsp;or&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">foo.behavior(x)</code>. The problems with this are that reserving a keyword is undesirable, and that&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">behavior</code>&nbsp;is a vague term that requires more context for a reader to understand what’s going on. If we support multiple behaviors on a property, it also doesn’t provide a mechanism to distinguish between behaviors.</li><li class="">Something following the property name, such a&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">foo.x«lazy»</code>&nbsp;or&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">foo.x¶lazy</code>&nbsp;(choosing your favorite ASCII substitution for&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">«»¶</code>, again), to match the similar proposed declaration syntax above.</li><li class="">“Overloading” the property name to refer to both the declared property and its backing property, and doing member lookup in both (favoring the declared property when there are conflicts). If&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">foo.x</code>&nbsp;is known to be&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">lazy</code>, it’s attractive for&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">foo.x.clear()</code>&nbsp;to Just Work without annotation. This has the usual ambiguity problems of overloading, of course; if the behavior’s members are shadowed by the fronting type, something incovenient like&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">(foo.x as Lazy).clear()</code>&nbsp;would be necessary to disambiguate.</li></ul><h3 id="definingbehaviorrequirementsusingaprotocol" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 18px; color: rgb(51, 51, 51); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">Defining behavior requirements using a protocol</h3><p style="margin: 0px 0px 15px;" class="">It’s reasonable to ask why the behavior interface proposed here is ad-hoc rather than modeled as a formal protocol. It’s my feeling that a protocol would be too constraining:</p><ul style="padding-left: 30px;" class=""><li class="">Different behaviors need the flexibility to require different sets of property attributes. Some kinds of property support initializers; some kinds of property have special accessors; some kinds of property support many different configurations. Allowing overloading (and adding new functionality via&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">extension</code>s and overloading) is important expressivity.</li><li class="">Different behaviors place different constraints on what containers are allowed to contain properties using the behavior, meaning that&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">subscript</code>&nbsp;needs the freedom to impose different generic constraints on its&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">varIn</code>/&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">letIn</code>&nbsp;parameter for different behaviors.</li></ul><p style="margin: 15px 0px;" class="">It’s true that there are type system features we could theoretically add to support these features in a protocol, but increasing the complexity of the type system has its own tradeoffs. I think it’s unlikely that behaviors would be useful in generics either.</p><h3 id="abehaviordeclaration" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 18px; color: rgb(51, 51, 51); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">A&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px;" class="">behavior</code>&nbsp;declaration</h3><p style="margin: 0px 0px 15px;" class="">Instead of relying entirely on an informal protocol, we could add a new declaration to the language to declare a behavior, something like this:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="swift" style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);">behavior lazy&lt;T&gt; {
  func lazy(...) -&gt; Lazy { ... }
  struct Lazy { var value: T; ... }
}</code></pre><p style="margin: 15px 0px;" class="">Doing this has some potential advantages:</p><ul style="padding-left: 30px;" class=""><li class="">It provides clear namespacing for things that are intended to be behaviors.</li><li class="">If the functions and types that implement the behavior can be nested under the behavior declaration somehow, then they don’t need to pollute the global function/type namespace.</li><li class="">The behavior declaration can explicitly provide metadata about the behavior, such as what container and value types it supports, what kinds of accessors properties can provide to it, that are all discovered by overload resolution in this proposal. It’d also be a natural place to place extensions like how a behavior behaves with overriding, what behaviors it can or can’t compose with, etc.</li></ul><h3 id="namingconventionforbehaviors" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 18px; color: rgb(51, 51, 51); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">Naming convention for behaviors</h3><p style="margin: 0px 0px 15px;" class="">This proposal doesn’t discuss the naming convention that behaviors should follow. Should they be random adjectives like&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">lazy</code>? Should we try to follow an&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">-ing</code>&nbsp;or&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">-able</code>&nbsp;suffix convention? Does it matter, if behaviors have their own syntax namespace?</p><h2 id="todo" style="margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: subpixel-antialiased; cursor: text; font-size: 24px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(204, 204, 204); transition: background-color 0.2s ease-out; -webkit-transition: background-color 0.2s ease-out;" class="">TODO</h2><p style="margin: 0px 0px 15px;" class="">When do properties with behaviors get included in the memberwise initializer of structs or classes, if ever? Can properties with behaviors be initialized from&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">init</code>&nbsp;rather than with inline initializers?</p><p style="margin: 15px 0px;" class="">Can behaviors be composed, e.g.&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">(lazy, observed)</code>, or&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">(lazy, atomic)</code>? How? Composition necessarily has to have an ordering, and some orderings will be wrong; e.g. one of&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">(lazy, atomic)</code>&nbsp;or&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">(atomic, lazy)</code>&nbsp;will be broken.</p><p style="margin: 15px 0px;" class="">To be able to fully supplant&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">didSet</code>/<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">willSet</code>&nbsp;(and addressors), we’d need to be able to give behaviors to subscripts as well. The special&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">override</code>&nbsp;behavior of&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">didSet</code>/<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">willSet</code>&nbsp;in subclasses needs to be accounted for as well.</p><p style="margin: 15px 0px;" class="">It’s worth considering what the “primitive” interface for properties is; after all, theoretically even computed properties could be considered a behavior if you unstack enough turtles. One key thing to support that I don’t think our current special-case accessors handle is conditional physical access. For instance, a behavior might want to pass through to its physical property, unless some form of transactionality is enabled. As a strawman, if there were an&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">inout</code>&nbsp;accessor, which received the continuation of the property access as an&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">(inout T) -&gt; Void</code>&nbsp;parameter, that might be expressed like this:</p><pre style="margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code style="margin: 0px; padding: 0px; border: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">var _x = 0
var x: Int {
  inout(continuation) {
    // If we're not logging, short-circuit to a physical access of `x`.
    if !logging {
      continuation(&amp;_x)
      return
    }
    // Otherwise, save the oldValue and log before and after
    let oldValue = x
    var newValue = x
    continuation(&amp;newValue)
    print("--- changing _x from \(oldValue) to \(newValue)")
    _x = newValue
    print("--- changed! _x from \(oldValue) to \(newValue)")
  }
}</code></pre><p style="margin-top: 15px; margin-right: 0px; margin-bottom: 0px !important; margin-left: 0px;" class="">An implementation of&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">inout</code>&nbsp;as proposed like this could be unrolled into a&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">materializeForSet</code>&nbsp;implementation using a SIL state machine transform, similar to what one would do to implement&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">yield</code>&nbsp;or&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">await</code>, which would check that&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">continuation</code>&nbsp;always gets called exactly once on all paths and capture the control flow after the continuation call in the&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; color: rgb(51, 51, 51);" class="">materializeForSet</code>&nbsp;continuation.</p></div><div id="generated-toc" class="generate_from_h1 generate_for_page" style="position: fixed; max-height: 90%; width: 250px; overflow-x: hidden; overflow-y: auto; right: 20px; bottom: -972px; font-size: 1.1em; line-height: 1.2em; background-color: rgba(0, 0, 0, 0.8); color: rgb(200, 200, 200); padding: 10px 30px 20px 20px; border-top-left-radius: 10px; border-top-right-radius: 10px; border-bottom-right-radius: 10px; border-bottom-left-radius: 10px; transition: all 0.3s ease-out; -webkit-transition: all 0.3s ease-out; word-wrap: break-word; z-index: 101; outline: 0px; border: 0px; font-family: -webkit-standard;"><p style="margin: 15px 0px;" class=""><span class="hidden"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#aftertoc" style="color: rgb(255, 255, 255) !important; text-decoration: none; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; background-position: initial initial !important; background-repeat: initial initial !important;" class=""></a></span></p><p id="toggle-container" style="margin: 15px 0px;" class=""><a id="generated_toc_d_toggle" href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#" style="color: rgb(255, 255, 255) !important; text-decoration: none; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; background-position: initial initial !important; background-repeat: initial initial !important;" class=""></a></p><ul style="padding-left: 0px; margin-left: 10px;" class=""><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#propertybehaviors" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">Property Behaviors</a><ul style="padding-left: 0px; margin-left: 10px;" class=""><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#introduction" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">Introduction</a></li><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#motivation" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">Motivation</a></li><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#proposedsolution" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">Proposed solution</a></li><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#examples" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">Examples</a><ul style="padding-left: 0px; margin-left: 10px;" class=""><li class="missing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><ul style="padding-left: 0px; margin-top: 0px; margin-left: 10px;" class=""><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#lazy" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">Lazy</a></li><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#memoization" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">Memoization</a></li><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#delayedinitialization" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">Delayed Initialization</a></li><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#resettableproperties" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">Resettable properties</a></li><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#synchronizedpropertyaccess" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">Synchronized Property Access</a></li><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#nscopying" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">NSCopying</a></li><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#referencingpropertieswithpointers" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">Referencing Properties with Pointers</a></li><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#propertyobservers" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">Property Observers</a></li></ul></li></ul></li><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#detaileddesign" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">Detailed design</a></li><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#impactonexistingcode" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">Impact on existing code</a></li><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#alternativesconsideredtoconsider" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">Alternatives considered/to consider</a><ul style="padding-left: 0px; margin-left: 10px;" class=""><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#declarationsyntax" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">Declaration syntax</a></li><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#syntaxforaccessingthebackingproperty" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">Syntax for accessing the backing property</a></li><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#definingbehaviorrequirementsusingaprotocol" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">Defining behavior requirements using a protocol</a></li><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#abehaviordeclaration" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">A behavior declaration</a></li><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#namingconventionforbehaviors" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">Naming convention for behaviors</a></li></ul></li><li class="notmissing" style="display: block; list-style: none; margin: 10px 0px; background-color: transparent !important; background-position: initial initial !important; background-repeat: initial initial !important;"><a href="file:///Users/jgroff/src/s/swift-evolution/proposals/XXXX-property-delegates.md#todo" class="wiki-link" style="color: rgb(255, 255, 255) !important; text-decoration: none; margin-top: 0px; display: block; font-size: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; border: none !important; background-image: none !important; outline: 0px; background-position: initial initial !important; background-repeat: initial initial !important;">TODO</a></li></ul></li></ul></div><div class=""><br class=""></div></div>
<img src="https://u2002410.ct.sendgrid.net/wf/open?upn=eLFMrKDT8iBxZ-2Fbnk-2BZqvSchNN-2FvYXdceA0T7VxwkAfSEewakMxbaP2dtiLgr5kvCwVNa7HL-2B9fYRx-2FtPYCoakRfX4UbNhwsU3TVFT3pdC4KAUGCPhSoqsscltR7wjc5eOydkWrGniZNiW5HUYjGLi0ALFZUfyfsfXw4-2B8gCOUZJ-2F8lQ99n1gbbumS8Ga82DWEgdjGUB0QCFqa3YT2yjcg2L4cNlOQZ5lr-2BklVK5pPI-3D" alt="" width="1" height="1" border="0" style="height:1px !important;width:1px !important;border-width:0 !important;margin-top:0 !important;margin-bottom:0 !important;margin-right:0 !important;margin-left:0 !important;padding-top:0 !important;padding-bottom:0 !important;padding-right:0 !important;padding-left:0 !important;" class="">
</div>
_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></blockquote></div><br class=""></div></div></div></body></html>