Optional variables from a non-optional source with type inference


(Michael Henson) #1

While reading the summary of a newsletter's notification about the
acceptance of SE-0021's new syntax, a thought occurred to me:

let fn = someView.insertSubview(_:at:)

let fn1 = someView.insertSubview(_:aboveSubview:)
let fn2 = someView.insertSubview(_:belowSubview:)

That code will create variables fn, fn1, fn2 of the correct type to hold
each of the named functions.

As I understand it, the following things are true:

1. Member functions on instances of a class type are curried functions that
strongly capture 'self'.
2. Any strong reference to those member functions will also prevent that
instance from ever reaching ref count 0.
3. This isn't a new problem, just one that will become more important now
that this use case is easier to... use.

The easy fix for this situation would be to declare fn, fn1, and fn2 as
weakened optionals so they don't keep someView around if it should have
been dallocated. The question is... how? Is there existing syntax that
means "infer the type from the right-hand-side production, except as an
optional / weakened optional"?

Mike


(Jordan Rose) #2

Hey, Mike. There's no existing syntax for this today; the best you can get is a custom closure. The type can still be inferred, though:

let fn3 = { [weak someView] in someView?.insertSubview($0, belowSubview: $1) }

This works because the closure is a single expression, so the body can be type-checked together with the enclosing statement. If the body has actual statements in it then it is type-checked separately.

We don't currently have any other syntax for this, but personally I think it's not common enough to warrant it. I'd actually rather consider disallowing binding member functions like this unless the resulting closure is @noescape. That also keeps you from accidentally introducing retain cycles. But any serious language change here would have to go through the Swift Evolution Process <https://github.com/apple/swift-evolution/blob/master/process.md>.

Best,
Jordan

···

On Jan 25, 2016, at 16:16 , Michael Henson via swift-users <swift-users@swift.org> wrote:

While reading the summary of a newsletter's notification about the acceptance of SE-0021's new syntax, a thought occurred to me:

let fn = someView.insertSubview(_:at:)
let fn1 = someView.insertSubview(_:aboveSubview:)
let fn2 = someView.insertSubview(_:belowSubview:)

That code will create variables fn, fn1, fn2 of the correct type to hold each of the named functions.

As I understand it, the following things are true:

1. Member functions on instances of a class type are curried functions that strongly capture 'self'.
2. Any strong reference to those member functions will also prevent that instance from ever reaching ref count 0.
3. This isn't a new problem, just one that will become more important now that this use case is easier to... use.

The easy fix for this situation would be to declare fn, fn1, and fn2 as weakened optionals so they don't keep someView around if it should have been dallocated. The question is... how? Is there existing syntax that means "infer the type from the right-hand-side production, except as an optional / weakened optional"?


(Kevin Lundberg) #3

I wrote a small library a while back that handles this problem without
needing a new closure:
https://github.com/klundberg/weakify

...which should be SwiftPM compatible on top of the more established
distribution methods.

···

On 1/26/2016 10:39 PM, Jordan Rose via swift-users wrote:

On Jan 25, 2016, at 16:16 , Michael Henson via swift-users >> <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

While reading the summary of a newsletter's notification about the
acceptance of SE-0021's new syntax, a thought occurred to me:

    let fn = someView.insertSubview(_:at:) |let fn1 =
    someView.insertSubview(_:aboveSubview:)
    >>let fn2 = someView.insertSubview(_:belowSubview:)|

That code will create variables fn, fn1, fn2 of the correct type to
hold each of the named functions.

As I understand it, the following things are true:

1. Member functions on instances of a class type are curried
functions that strongly capture 'self'.
2. Any strong reference to those member functions will also prevent
that instance from ever reaching ref count 0.
3. This isn't a new problem, just one that will become more important
now that this use case is easier to... use.

The easy fix for this situation would be to declare fn, fn1, and fn2
as weakened optionals so they don't keep someView around if it should
have been dallocated. The question is... how? Is there existing
syntax that means "infer the type from the right-hand-side
production, except as an optional / weakened optional"?

Hey, Mike. There's no existing syntax for this today; the best you can
get is a custom closure. The type can still be inferred, though:

    let fn3 = { [weak someView] in someView?.insertSubview($0,
    belowSubview: $1) }

This works because the closure is a single expression, so the body can
be type-checked together with the enclosing statement. If the body has
actual statements in it then it is type-checked separately.

We don't currently have any other syntax for this, but personally I
think it's not common enough to warrant it. I'd actually rather
consider /disallowing/ binding member functions like this unless the
resulting closure is @noescape. That also keeps you from accidentally
introducing retain cycles. But any serious language change here would
have to go through the Swift Evolution Process
<https://github.com/apple/swift-evolution/blob/master/process.md>.

Best,
Jordan

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