Keeping unused values around until containing scope exits?


(Ollie Wagner) #1

I'm using the lifetime of a variable to push and pop a context in an animation system that I'm writing. I'm interested in using a pattern like:

func doAnimations() {
    AnimationContext(speed: 1.0, bounciness: 1.0)
    // do some animations using these options
}

But today, the value returned by AnimationContext(speed:bounciness:) gets deinitted immediately.

I've come to desire using such a pattern after living with this for a while:

AnimationContext(speed: 1.0, bounciness: 1.0) {
    // do some animations using these options
}

But I don't like it because it contributes heavily to rightward drift (a user of this API might want to change the options multiple times), and gets hard to parse when nested in the many other language constructs that create a scope using brackets.

So — would it be reasonable to suggest that we have some keyword(s) preceeding an initializer that allows a value to stay alive and/or not warn if it winds up going unused? The current behavior in Swift has obviously been considered, so please feel free to tell me if this is a Very Bad Idea. I'm still learning!

- Ollie


(Joe Groff) #2

I'm using the lifetime of a variable to push and pop a context in an animation system that I'm writing. I'm interested in using a pattern like:

func doAnimations() {
    AnimationContext(speed: 1.0, bounciness: 1.0)
    // do some animations using these options
}

But today, the value returned by AnimationContext(speed:bounciness:) gets deinitted immediately.

I've come to desire using such a pattern after living with this for a while:

AnimationContext(speed: 1.0, bounciness: 1.0) {
    // do some animations using these options
}

But I don't like it because it contributes heavily to rightward drift (a user of this API might want to change the options multiple times), and gets hard to parse when nested in the many other language constructs that create a scope using brackets.

There's a standard function withExtendedLifetime which you can use for this already:

withExtendedLifetime(AnimationContext(...)) {
   // AnimationContext is guaranteed to be alive in this block
}

though that doesn't solve the rightward drift problem. You can alternately defer { } an artificial use of the object:

@inline(never) func use(x: Any) { }

let x = AnimationContext(...); defer { use(x) }

As discussed in the "scoped resources" thread, we might also benefit from something like ObjC ARC's scoped lifetime attribute.

So — would it be reasonable to suggest that we have some keyword(s) preceeding an initializer that allows a value to stay alive and/or not warn if it winds up going unused? The current behavior in Swift has obviously been considered, so please feel free to tell me if this is a Very Bad Idea. I'm still learning!

The vast majority of objects only own resources that are only necessary for that object's own operation, and most of Swift's target platforms are resource-constrained, so it's a valuable optimization to be able to deallocate objects ASAP. We think it's a reasonable tradeoff for objects which do require fixed scopes to require a bit of additional annotation.

-Joe

···

On Dec 30, 2015, at 10:10 AM, Ollie Wagner via swift-evolution <swift-evolution@swift.org> wrote:


(Lily Ballard) #3

I strongly recommend either making the context get explicitly used in the subsequent animations (e.g. `context.animation(...)` instead of just `animation(...)`) or giving it an explicit scope (e.g. `withAnimationContext(speed: 1.0, bounciness: 1.0) { ... }`). Having the presence of a stack value influence behavior is a great way to cause maintenance issues later on.

-Kevin Ballard

···

On Wed, Dec 30, 2015, at 10:10 AM, Ollie Wagner via swift-evolution wrote:

I'm using the lifetime of a variable to push and pop a context in
an animation system that I'm writing. I'm interested in using a
pattern like:

func doAnimations() { AnimationContext(speed: 1.0, bounciness: 1.0)
// do some animations using these options }

But today, the value returned by AnimationContext(speed:bounciness:)
gets deinitted immediately.

I've come to desire using such a pattern after living with this for
a while:

AnimationContext(speed: 1.0, bounciness: 1.0) { // do some
animations using these options }

But I don't like it because it contributes heavily to rightward drift
(a user of this API might want to change the options multiple times),
and gets hard to parse when nested in the many other language
constructs that create a scope using brackets.

So — would it be reasonable to suggest that we have some keyword(s)
preceeding an initializer that allows a value to stay alive and/or not
warn if it winds up going unused? The current behavior in Swift has
obviously been considered, so please feel free to tell me if this is a
Very Bad Idea. I'm still learning!

- Ollie

_________________________________________________
swift-evolution mailing list swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Kevin Wooten) #4

I strongly recommend either making the context get explicitly used in the subsequent animations (e.g. `context.animation(...)` instead of just `animation(...)`) or giving it an explicit scope (e.g. `withAnimationContext(speed: 1.0, bounciness: 1.0) { ... }`). Having the presence of a stack value influence behavior is a great way to cause maintenance issues later on.

-Kevin Ballard

I'm using the lifetime of a variable to push and pop a context in an animation system that I'm writing. I'm interested in using a pattern like:

func doAnimations() {
    AnimationContext(speed: 1.0, bounciness: 1.0)
    // do some animations using these options
}

But today, the value returned by AnimationContext(speed:bounciness:) gets deinitted immediately.

I've come to desire using such a pattern after living with this for a while:

AnimationContext(speed: 1.0, bounciness: 1.0) {
    // do some animations using these options
}

But I don't like it because it contributes heavily to rightward drift (a user of this API might want to change the options multiple times), and gets hard to parse when nested in the many other language constructs that create a scope using brackets.

Not sure how contrived your code example is but in the given example wouldn’t just chaining off of AnimationContext solve rightward drift?

AnimationContext(speed: 1, bounciness: 1) {
  ...
}.changeSpeed(to: 2) {
  ...
}

···

On Dec 30, 2015, at 5:38 PM, Kevin Ballard via swift-evolution <swift-evolution@swift.org> wrote:
On Wed, Dec 30, 2015, at 10:10 AM, Ollie Wagner via swift-evolution wrote:

So — would it be reasonable to suggest that we have some keyword(s) preceeding an initializer that allows a value to stay alive and/or not warn if it winds up going unused? The current behavior in Swift has obviously been considered, so please feel free to tell me if this is a Very Bad Idea. I'm still learning!

- Ollie

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution