<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="">Yes. I'm working on a revision I hope to post soon.<div class=""><br class=""></div><div class="">-Joe</div><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Jan 13, 2016, at 7:36 AM, Wallacy <<a href="mailto:wallacyf@gmail.com" class="">wallacyf@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">Just to clarify a little, this proposal is (will be) addressed to 3.0?<br class=""><br class=""><div class="gmail_quote"><div dir="ltr" class="">Em qui, 17 de dez de 2015 às 15:41, Joe Groff via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> escreveu:<br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" 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" target="_blank" class="">https://gist.github.com/jckarter/f3d392cf183c6b2b2ac3</a></div><div class=""><br class=""></div><div class=""><div style="font-size:14px;font-family:helvetica,arial,freesans,clean,sans-serif;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;outline:0px;border:0px" class=""><h1 style="margin-right:0px;margin-bottom:10px;margin-left:0px;padding:0px;font-size:28px;margin-top:0px!important" class="">Property Behaviors</h1><ul style="padding-left:30px" class=""><li class="">Proposal: <a href="https://github.com/apple/swift-evolution/proposals/NNNN-name.md" style="color:rgb(65,131,196);text-decoration:none;margin-top:0px" target="_blank" class="">SE-NNNN</a></li><li class="">Author(s): <a href="https://github.com/jckarter" style="color:rgb(65,131,196);text-decoration:none;margin-top:0px" target="_blank" class="">Joe Groff</a></li><li class="">Status: <strong style="margin-top:0px" class="">Review</strong></li><li class="">Review manager: TBD</li></ul><h2 style="margin:20px 0px 10px;padding:0px;font-size:24px;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(204,204,204)" 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 style="margin:20px 0px 10px;padding:0px;font-size:24px;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(204,204,204)" 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 <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> properties as a primitive language feature, since lazy initialization is common and is often necessary to avoid having properties be exposed as <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 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="">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 <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> 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 <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 <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> is also problematic for value types. A <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 <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 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="">class MemoizationBox<T> {
var value: T? = nil
init() {}
func getOrEvaluate(fn: () -> T) -> 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<String>()
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 <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 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="">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 <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> 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 style="margin:20px 0px 10px;padding:0px;font-size:24px;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(204,204,204)" class="">Proposed solution</h2><p style="margin:0px 0px 15px" class="">I suggest we allow for <strong class="">property behaviors</strong> to be implemented within the language. A <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 <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> 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 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 (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 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 `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 <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 <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> 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 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.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 <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 style="margin:20px 0px 10px;padding:0px;font-size:24px;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(204,204,204)" 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 style="margin:20px 0px 10px;padding:0px;font-size:16px;color:rgb(51,51,51)" class="">Lazy</h4><p style="margin:0px 0px 15px" class="">The current <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> 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 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="">public struct Lazy<Value> {
var value: Value?
public init() {
value = nil
}
public subscript<Container>(varIn _: Container,
initializer initial: () -> Value) -> Value {
mutating get {
if let existingValue = value {
return existingValue
}
let initialValue = initial()
value = initialValue
return initialValue
}
set {
value = newValue
}
}
}
public func lazy<Value>(var type: Value.Type, initializer _: () -> Value)
-> Lazy<Value> {
return Lazy()
}</code></pre><p style="margin:15px 0px" class="">As mentioned above, <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> 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 <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> 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 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="">extension Lazy {
public mutating func clear() {
value = nil
}
}
var (lazy) x = somethingThatEatsMemory()
use(x)
x.lazy.clear()</code></pre><h4 style="margin:20px 0px 10px;padding:0px;font-size:16px;color:rgb(51,51,51)" class="">Memoization</h4><p style="margin:0px 0px 15px" class="">Variations of <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> can be implemented that are more appropriate for certain situations. For instance, here’s a <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 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="">public class MemoizationBox<Value> {
var value: Value? = nil
init() {}
func getOrEvaluate(fn: () -> Value) -> 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<Container>(letIn _: Container,
initializer value: () -> Value) -> Value {
return box.getOrEvaluate(value)
}
}
public func memoized<Value>(let type: Value.Type, initializer: () -> Value)
-> MemoizationBox<Value> {
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 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="">struct Location {
let street, city, postalCode: String
let (memoized) address = "\(street)\n\(city) \(postalCode)"
}</code></pre><h4 style="margin:20px 0px 10px;padding:0px;font-size:16px;color:rgb(51,51,51)" class="">Delayed Initialization</h4><p style="margin:0px 0px 15px" class="">A property behavior can model “delayed” initialization behavior, where the DI rules for <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> and <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> 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 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="">public func delayed<Value>(let type: Value.Type) -> Delayed<Value> {
return Delayed()
}
public func delayed<Value>(var type: Value.Type) -> Delayed<Value> {
return Delayed()
}
public struct Delayed<Value> {
var value: Value? = nil
/// DI rules for vars:
/// - Must be assigned before being read
public subscript<Container>(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<Container>(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 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="">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() -> Int {
return x // Will crash if 'self.x' wasn't initialized
}
}</code></pre><h4 style="margin:20px 0px 10px;padding:0px;font-size:16px;color:rgb(51,51,51)" 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 <em class="">set</em> to nil. If expressed as a behavior, the <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> 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 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="">public func resettable<Value>(var type: Value.Type,
initializer fallback: () -> Value) -> Resettable<Value> {
return Resettable(value: fallback())
}
public struct Resettable<Value> {
var value: Value?
public subscript<Container>(varIn container: Container,
initializer fallback: () -> Value) -> 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) // => 22
foo = 44
print(foo) // => 44
foo.resettable.reset()
print(foo) // => 22</code></pre><h4 style="margin:20px 0px 10px;padding:0px;font-size:16px;color:rgb(51,51,51)" class="">Synchronized Property Access</h4><p style="margin:0px 0px 15px" class="">Objective-C supports <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> properties, which take a lock on <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> and <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> 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 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="">// 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<R>(@noescape body: () -> R) -> R
}
public func synchronized<Value>(var _: Value.Type,
initializer initial: () -> Value)
-> Synchronized<Value> {
return Synchronized(value: initial())
}
public struct Synchronized<Value> {
var value: Value
public subscript<Container: Synchronizable>(varIn container: Container,
initializer _: () -> Value)
-> Value {
get {
return container.withLock {
return value
}
}
set {
container.withLock {
value = newValue
}
}
}
}</code></pre><h4 style="margin:20px 0px 10px;padding:0px;font-size:16px;color:rgb(51,51,51)" 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 <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> attribute for properties to give them behavior like Objective-C’s <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 <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> 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 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="">public func copying<Value: NSCopying>(var _: Value.Type,
initializer initial: () -> Value)
-> Copying<Value> {
return Copying(value: initial().copy())
}
public struct Copying<Value> {
var value: Value
public subscript<Container>(varIn container: Container,
initializer _: () -> Value)
-> Value {
get {
return value
}
set {
value = newValue.copy()
}
}
}</code></pre><h4 style="margin:20px 0px 10px;padding:0px;font-size:16px;color:rgb(51,51,51)" 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 <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> 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 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="">public func pointable<Value>(var _: Value.Type,
initializer initial: () -> Value)
-> Pointable<Value> {
return Pointable(value: initial())
}
public class Pointable<Value> {
public let pointer: UnsafeMutablePointer<Value>
init(value: Value) {
pointer = .alloc(1)
pointer.initialize(value)
}
deinit {
pointer.destroy()
pointer.dealloc(1)
}
public subscript<Container>(varIn _: Container,
initializer _: () -> Value)
-> 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) // => 44</code></pre><p style="margin:15px 0px" class="">(Manually allocating and deallocating a pointer in a <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> 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 style="margin:20px 0px 10px;padding:0px;font-size:16px;color:rgb(51,51,51)" class="">Property Observers</h4><p style="margin:0px 0px 15px" class="">A property behavior can also replicate the built-in behavior of <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> 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 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="">typealias ObservingAccessor = (oldValue: Value, newValue: Value) -> ()
public func observed<Value>(var _: Value.Type,
initializer initial: () -> Value,
didSet _: ObservingAccessor = {},
willSet _: ObservingAccessor = {})
-> Observed<Value> {
return Observed(value: initial())
}
public struct Observed<Value> {
var value: Value
public subscript<Container>(varIn _: Container,
initializer _: () -> Value,
didSet didSet: ObservingAccessor = {},
willSet willSet: ObservingAccessor = {})
-> 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 <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> is that the observers fire on <em class="">every</em> write, not only ones that cause a real change. A behavior that supports a <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> 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 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="">public func changeObserved<Value: Equatable>(var _: Value.Type,
initializer initial: () -> Value,
didChange _: ObservingAccessor = {})
-> ChangeObserved<Value> {
return ChangeObserved(value: initial())
}
public struct ChangeObserved<Value: Equatable> {
var value: Value
public subscript<Container>(varIn _: Container,
initializer _: () -> 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 style="display:block;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 style="margin:20px 0px 10px;padding:0px;font-size:24px;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(204,204,204)" class="">Detailed design</h2><p style="margin:0px 0px 15px" class="">A property declaration can declare a <strong class="">behavior</strong> after the <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 <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> 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 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 (runcible) foo: Int</code></pre><p style="margin:15px 0px" class="">(Possible alternatives to <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> are discussed later.) Inside the parens is a dotted declaration reference that must refer to a <strong class="">behavior function</strong> 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 <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 <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> (or <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 <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> as the first argument (or <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> 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 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 `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 <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>, etc. accessors from the behavior’s subscript declaration. By forwarding to a subscript instead of separate <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> and <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> 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 <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> for a <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 <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> for a <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 <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="">() -> T</code> closure to an argument labeled <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 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 (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 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 `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 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 (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 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="">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 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="">func runcible<T>(var type: T.Type, bar: (newValue: T) -> ())
-> RuncibleProperty<T></code></pre><p style="margin:15px 0px" class="">then a <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> accessor using this behavior can implicitly receive <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> 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 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 (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 <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> member with labeled index arguments:</p><ul style="padding-left:30px" class=""><li class="">The <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> value that contains the property is passed to a labeled <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> argument for a <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 <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> argument for a <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 <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> for a global or local property.</li><li class="">After these arguments, the subscript must take the same labeled <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> and/or accessor closure arguments as the behavior function.</li></ul><p style="margin:15px 0px" class="">It is an error if a matching <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> can’t be found on the type. By constraining what types are allowed to be passed to the <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> or <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> 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 <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> 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 <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 <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> as well.</p><p style="margin:15px 0px" class="">Some behaviors may have special operations associated with them; for instance, a <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> property may provide a way to <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> 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 <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 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 (lazy) x = somethingThatEatsMemory()
use(x)
x.lazy.clear() // free the memory</code></pre><p style="margin:15px 0px" class="">The backing property has <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> visibility by default (or <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 declared property is <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 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="">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 <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> property. It is the responsibility of a <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> property behavior’s implementation to provide the expected behavior of an immutable property over it. A well behaved <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> should produce an identical value every time it is loaded, or die trying, as in the case of an uninitialized <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> let. A <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> 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 style="margin:20px 0px 10px;padding:0px;font-size:24px;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(204,204,204)" 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 <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>, <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 <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> 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 <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> 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 <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> and addressors completely would require being able to apply behaviors to subscripts in addition to properties, which seems like a reasonable generalization.</p><h2 style="margin:20px 0px 10px;padding:0px;font-size:24px;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(204,204,204)" class="">Alternatives considered/to consider</h2><h3 style="margin:20px 0px 10px;padding:0px;font-size:18px;color:rgb(51,51,51)" class="">Declaration syntax</h3><p style="margin:0px 0px 15px" class="">Alternatives to the proposed <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> syntax include:</p><ul style="padding-left:30px" class=""><li class="">An attribute, such as <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> or <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. <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> 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 <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> attribute too).</li><li class="">Use a new keyword, as in <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 <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 <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> is a type of some kind, which it really isn’t.</li><li class="">Something following the property name, such as <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> or <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> (picking your favorite ASCII characters to replace <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 <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> as a declaration-follows-use way of accessing the backing property.</li></ul><h3 style="margin:20px 0px 10px;padding:0px;font-size:18px;color:rgb(51,51,51)" class="">Syntax for accessing the backing property</h3><p style="margin:0px 0px 15px" class="">The proposal suggests <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> for accessing the underlying backing property of <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 <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> or <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 <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> 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 <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> or <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> (choosing your favorite ASCII substitution for <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 <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> is known to be <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 <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> 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 <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> would be necessary to disambiguate.</li></ul><h3 style="margin:20px 0px 10px;padding:0px;font-size:18px;color:rgb(51,51,51)" 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 <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 <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> needs the freedom to impose different generic constraints on its <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></li></ul></div></div></div></blockquote></div></div>
</div></blockquote></div><br class=""></div></body></html>