[swift-evolution] [Proposal] Property behaviors

Wallacy wallacyf at gmail.com
Thu Jan 14 12:43:09 CST 2016


I really liked this idea:

x..resettablet.reset()

I can see that when typing the second dot, the autocomplete offering me all
behaviors available. ;)

And thinking a little, may the `pipe` can be used to declaration :

var |lazy| number = 1243

The Square brackets is good, but feels like array.

And for multiple behaviors, we can use the "*>*" to infer the "direction"
of the "composability":

var |lazy>observed| observedLazy = expensiveExpression() {
  didSet { print("\(oldValue) => \(observedLazy)") }
}



Em qui, 14 de jan de 2016 às 02:08, Joe Groff via swift-evolution <
swift-evolution at swift.org> escreveu:

> On Jan 13, 2016, at 7:13 PM, Félix Cloutier <felixcca at yahoo.ca> wrote:
>
> I started by reading the examples and I was very confused. This suggests
> to me that if you've never seen a var behavior before, you are going to
> wonder what the hell is going on. :-)
>
>
> This is good feedback, thanks!
>
> Notable points of confusion:
>
>
>    - it's confusing to me that `self` is the containing type and the
>    behavior name is the "behavior's self".
>
>
> Others have noted this too. Would it be less confusing if one had to
> explicitly name the "container" as a member, e.g.:
>
> var behavior synchronized {
>   container var parent: Synchronizable
>   base var value: Value
>
>   get {
>     return parent.withLock { value }
>   }
>   set {
>     parent.withLock { value = newValue }
>   }
> }
>
>
>
>    - The `initializer` special field feels absolutely magic. Has anything
>    else been considered, like an init param that has either a Value or an
>    autoclosure returning one? (If we don't want to capture self, aren't we in
>    for problems capturing self from accessors anyway?)
>
>
> An `init` parameter covers use cases where the initializer expression is
> used only during initialization, but doesn't let you use the initializer
> after initialization, which is necessary for `lazy`, `resettable`, and
> other use cases. Even with @autoclosure, it seems to me that, without
> `initializer`, we'd need to allocate per-property storage for the
> initializer expression to use it later, which is something I'd like to
> avoid.
>
>
>    - I see (after reading it) that `var behavior foo<Value>: Value` means
>    that foo "applies to"/"wraps" Value, but I find it confusing to use a
>    syntax more typically associated with "extends" or "implements" or "is a".
>
>
> Would it be less confusing if the type of the property were implicit? In
> discussion with Brent, I suggested a model where you say:
>
> var behavior foo { ... }
>
>
> and if you want to constrain the types of properties that can instantiate
> the behavior, you use a where clause:
>
> var behavior foo where Value: NSCopying { ... }
>
> which optimizes the common case (no constraint), and might be easier to
> read.
>
> Questions:
>
>
>    - Can a behavior have generic parameters that can't be inferred? Could
>    I write, say, [fooable<Int>]?
>
>
> No, the generic parameters are only used to generalize the property type.
>
>
>    - What is the tradeoff between `eager` and `deferred`? Is it "only"
>    that `deferred` side effects happen at the mercy of the behavior?
>       - If so, isn't it a problem that behaviors aren't intrinsically
>       explicit about whether they defer initialization? I can see that causing
>       very subtle bugs.
>
>
> The tradeoff is that an 'eager' initialization can be used in `init`, but
> that means that an initializer expression can't refer to `self`, because
> `self` is not fully initialized. This is how initializer expressions always
> work today:
>
> struct X {
>   var x = 0, y = 1
>   var z = x + y // Error
> }
>
> A deferred initialization can only be evaluated *after* init, but because
> of that, it can refer to `self`, which people would like to be able to do
> with `lazy` (but currently can't):
>
> struct X {
>   var x = 0, y = 1
>   lazy var z = x + y // Theoretically OK
> }
>
>
> Concerns:
>
>
>    - It looks like if you had a [resettable, observable] property,
>    calling resettable.reset() would change the value from under `observable`'s
>    feet.
>
>
> True. An unfortunate consequence of these things being user-defined is
> that there will always be "wrong" orderings of them. I'm not sure how much
> we can do about that.
>
>
> Comments:
>
>
>    - While it might be true that square brackets work better with other
>    declarations that could eventually have behaviors, "var behavior" doesn't
>    really lend itself to that kind of extensibility. Are we steering towards
>    "func behavior", "class behavior", etc? Is it a problem if we are?
>
>
> Possibly. Note that square brackets are necessary even only for `var`,
> because you can declare a destructuring binding `var (x, y) = tuple`.
>
>
>    - I'd like to point out that the memoization example is a let variable
>    with a behavior, which is explicitly forbidden by the current proposal.
>
>
> Thanks, missed that.
>
>
> Finally, I would like to throw the idea of "foo..resettable" to access
> foo's resettable behavior (or foo..reset() doing optionally-qualified
> lookup on foo's behavior methods).
>
>
> Not a bad suggestion.
>
> Thanks again for the feedback!
>
> -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/e497970c/attachment.html>


More information about the swift-evolution mailing list