<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=""><div class="">I have been thinking further about the compiler diagnostics for `delayed`. It might be interesting to consider making various compiler diagnostics available to any behavior rather than having a special case in the compiler for `delayed`. </div><div class=""><br class=""></div><div class="">Here are some examples:</div><div class=""><br class=""></div><div class="">* By default properties with a behavior must be initialized in phase one just like normal properties.</div><div class="">* Behaviors can opt-in to a relaxed requirement that the property must be initialized *somewhere* in the initializer, but not necessarily phase one. Delayed would opt-in to this.</div><div class="">* Behaviors can opt-in to a requirement that the property *cannot* be set outside of an initializer. Delayed would opt-in to this.</div><div class="">* Behaviors can opt-in to a requirement that the property *cannot* be set anywhere. A variation of lazy might opt-in to this. (clear would still work as it is part of the implementation of lazy)</div><div class=""><br class=""></div><div class="">Allowing behaviors to specify diagnostic behavior like this would probably be *possible* in the ad-hoc proposal. However, it would probably be a lot more clear and elegant if we adopt the “behavior declaration” idea.</div><div class=""><br class=""></div><div class="">Matthew</div><br class=""><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Dec 21, 2015, at 11:23 AM, Joe Groff via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">I played around a bit with the idea of a special behavior declaration. I think it feels a lot nicer, though it also feels like a much bigger language change if we go this route. Inside the declaration, you need to specify:<div class="">- what accessors the behavior supports, to be implemented by properties using the behavior,</div><div class="">- if the behavior controls storage, what that storage is, and what initialization logic it requires,</div><div class="">- if the behavior requires an initializer, and whether that initializer is used eagerly at property initialization or deferred to later, and</div><div class="">- what operations the behavior offers, if any.</div><div class=""><br class=""></div><div class="">Here's a quick sketch of how a behavior declaration could look. As a strawman, I'll use 'var behavior' as the introducer for a property behavior (leaving the door open to 'func behavior', 'struct behavior', etc. in the possible future). If you were going to reinvent computed properties from whole cloth, that might look like this:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class="">var behavior computed<T> {</div></div><div class=""> // A computed property requires a `get` and `set` accessor.</div><div class=""><div class=""> accessor get() -> T</div></div><div class=""><div class=""> accessor set(newValue: T)</div></div><div class=""><div class=""><br class=""></div></div><div class=""> // Accessors for the property</div><div class=""><div class=""> get { return get() }</div></div><div class=""><div class=""> set { set(newValue) }</div></div><div class=""><div class="">}</div></div></blockquote><div class=""><div class=""><br class=""></div></div><div class="">lazy might look something like this:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class="">var behavior lazy<T> {</div></div><div class=""> // lazy requires an initializer expression, but it isn't</div><div class=""> // used until after object initialization.</div><div class=""><div class=""> deferred initializer: T</div></div><div class=""><div class=""><br class=""></div></div><div class=""> // The optional storage for the property.</div><div class=""><div class=""> var value: T?</div></div><div class=""><div class=""><br class=""></div></div><div class=""> // Initialize the storage to nil.</div><div class=""><div class=""> init() {</div></div><div class=""><div class=""> value = nil</div></div><div class=""><div class=""> }</div></div><div class=""><div class=""><br class=""></div></div><div class=""> // Accessors for the property.</div><div class=""><div class=""> mutating get {</div></div><div class=""><div class=""> if let value = value {</div></div><div class=""><div class=""> return value</div></div><div class=""><div class=""> }</div></div><div class=""> // `initializer` is implicitly bound to the initializer expr as a</div><div class=""> // `@noescape () -> T` within the behavior's members.</div><div class=""><div class=""> let initialValue = initializer()</div></div><div class=""><div class=""> value = initialValue</div></div><div class=""><div class=""> return initialValue</div></div><div class=""><div class=""> }</div></div><div class=""><div class=""><br class=""></div></div><div class=""><div class=""> set {</div></div><div class=""><div class=""> value = newValue</div></div><div class=""><div class=""> }</div></div><div class=""><div class=""><br class=""></div></div><div class=""> // clear() operation for the behavior.</div><div class=""><div class=""> mutating func clear() {</div></div><div class=""><div class=""> value = nil</div></div><div class=""><div class=""> }</div></div><div class=""><div class="">}</div></div></blockquote><div class=""><div class=""><br class=""></div></div><div class="">Some behaviors like `lazy` and `resettable` want to take control of the storage to manage their semantics, but many behaviors are adapters independent of how the underlying behavior behaves. These kinds of behavior are easy to compose with other behaviors and to override base class properties with. You could use inheritance-like syntax to indicate a "wrapping" behavior like this, and commandeer `super` to refer to the underlying property. For instance, `synchronized`:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class="">var behavior synchronized<T>: T {</div></div><div class=""><div class=""> get {</div></div><div class=""><div class=""> return sync { return super }</div></div><div class=""><div class=""> }</div></div><div class=""><div class=""> set {</div></div><div class=""><div class=""> return sync { return super }</div></div><div class=""><div class=""> }</div></div><div class=""><div class="">}</div></div></blockquote><div class=""><div class=""><br class=""></div></div><div class="">or `observing` didSet/willSet:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class="">var behavior observing<T>: T {</div></div><div class=""><div class=""> accessor willSet(oldValue: T, newValue: T) { }</div></div><div class=""><div class=""> accessor didSet(oldValue: T, newValue: T) { }</div></div><div class=""><div class=""><br class=""></div></div><div class=""><div class=""> get { return super }</div></div><div class=""><div class=""> set {</div></div><div class=""> let oldValue = super</div><div class=""><div class=""> willSet(oldValue, newValue)</div></div><div class=""><div class=""> super = newValue</div></div><div class=""><div class=""> didSet(oldValue, newValue)</div></div><div class=""><div class=""> }</div></div><div class=""><div class="">}</div></div></blockquote><div class=""><br class=""></div><div class="">If you want to refer back to the containing `self`, we could support that too, and by treating behavior functions specially we should be able to maintain coherent semantics for backreferencing value types as well. Implementing `synchronized` with a per-object lock could look like this:</div><div class=""><br class=""></div><div class=""><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div class="">var behavior synchronizedByObject<T>: T where Self: Synchronizable {</div><div class=""> get {</div><div class=""> return self.withLock { return super }</div><div class=""> }</div><div class=""> set {</div><div class=""> return self.withLock { return super }</div><div class=""> }</div><div class="">}</div><div class=""><br class=""></div></blockquote>(though the juxtaposed meanings of `super` and `self` here are weird together…we'd probably want a better implicit binding name for the underlying property.)<div class=""></div></div><div class=""><br class=""></div><div class="">-Joe</div>
<img src="https://u2002410.ct.sendgrid.net/wf/open?upn=eLFMrKDT8iBxZ-2Fbnk-2BZqvSchNN-2FvYXdceA0T7VxwkAdB7f5kPel3wVVhZxLSddb-2FldjgOHakJarBMOyzAELLOuvB0h52c6hlV5Opv9Nqc9Z8EMVa3VYcHGKNDjHlrfGCTKQRmaVWUwLtvY9dMKtOJZnO9bG3Sym9sIOpYWxqPxlOADxujvnHBFqCiH3f0aqk39OZHV29ScuGERA4H56U3uY0oA55ORIisRewzOkvv-2Fk-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></body></html>