[swift-evolution] [Proposal] Property behaviors

Joe Groff jgroff at apple.com
Thu Jan 14 12:23:04 CST 2016


> On Jan 13, 2016, at 9:34 PM, David Waite <david at alkaline-solutions.com> wrote:
> 
> Joe,
> 
> There seem to be many new syntactic features to support this, both inside and outside of a behavior. I was wondering if you had considered/had comments an alternative approach where you declare an ordinary new value type which meets certain rules and ‘wraps’ the existing type, then define new syntax/features in Swift for having the wrapper (or possibly even multiple levels of wrappers) be more transparent for use.
> 
> For instance, the existing ‘lazy’ keyword functionality might have been implemented by a type  Lazy<T>
> 
> struct Lazy<T> {
>     private var val:T?
>     let supplier:()->T
>     
>     init(supplier:()->T) {
>         self.supplier = supplier
>     }
> 
>     var value:T {
>         mutating get {
>             if val == nil {
>                 val = supplier()
>             }
>             return val!
>         }
>         set {
>             val = value
>         }
>     }
>     mutating func clear() {
>         val = nil
>     }
> 
> }
> 
> With the following as an example of use (without any additional syntactic features)
> 
> var globally = "Test"
> class Foo {
>     var bar = Lazy<Int> {
>         globally = "Side effect"
>         return 1
>     }
> }
> 
> print(globally)
> Foo().bar.value
> print(globally)
> Foo().bar.clear()
> 
> One could opt into a syntax to allow value to be hidden from view. In fact, I can hide the use of the Lazy struct today if I’m willing to write more code:
> 
> class Foo {
>     private var internalbar = Lazy<Int> {
>         return 1
>     }
>     var bar:Int {
>         get {
>             return internalbar.value
>         }
>         set {
>             internalbar.value = newValue
>         }
>     }
> }
> print(Foo().bar)
> 
> Which actually has the benefit of being able to call the clear() method without new syntax, and being able to control access to clear separate from the getter/setter

Yes, this was explored by the previous iteration of the proposal. The exact design you propose is unacceptable for us, because it requires per-property instance storage for the "supplier" closure, which would be a massive regression from how `lazy` works today. To avoid this, the parameters of the property declaration need to be passed to the property implementation as well, so I had proposed using a subscript to handle it:

struct Lazy<T> {
  var value: T? = nil

  subscript(initialValue: () -> T) -> T { ... }
}

which is workable, but if we want this feature to have the flexibility to subsume all of our existing ad-hoc property features, the informal protocol between the behavior and the initialization and subscripting of the underlying type becomes fairly complex. Using types to encapsulate behaviors also introduces some runtime overhead we'd like to avoid if possible.

-Joe

> 
> -DW
> 
> 
>> On Jan 13, 2016, at 3:07 PM, Joe Groff via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> 
>> Thanks everyone for the first round of feedback on my behaviors proposal. I've revised it with the following changes:
>> 
>> - Instead of relying on mapping behaviors to function or type member lookup, I've introduced a new purpose-built 'var behavior' declaration, which declares the accessor and initializer requirements and provides the storage and behavior methods of the property. I think this gives a clearer design for authoring behaviors, and allows for a more efficient and flexible implementation model.
>> - I've backed off from trying to include 'let' behaviors. As many of you noted, it's better to tackle immutable computed properties more holistically than to try to backdoor them in.
>> - I suggest changing the declaration syntax to use a behavior to square brackets—'var [behavior] foo'—which avoids ambiguity with destructuring 'var' bindings, and also works with future candidates for behavior decoration, particularly `subscript`.
>> 
>> Here's the revised proposal:
>> 
>> https://gist.github.com/jckarter/50b838e7f036fe85eaa3 <https://gist.github.com/jckarter/50b838e7f036fe85eaa3>
>> 
>> For reference, here's the previous iteration:
>> 
>> https://gist.github.com/jckarter/f3d392cf183c6b2b2ac3
>> 
>> Thanks for taking a look!
>> 
>> -Joe
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160114/1a8a6ee8/attachment.html>


More information about the swift-evolution mailing list