Hi Matthew,

Thank you for the hint. Indeed, at first glance your proposal is very similar 
to my thinking. I’ll try to dive deeper into your proposal and find out more 
about the discussion behind it when I get some more time for that.

We could collaborate on a revision for Swift 5 if you would like to, but we 
wouldn’t need to rush now, because there is plenty of time for that.

Personally I would love to avoid some kind of a prefix like ? if possible.

Brainstorming:

let c1 = weak someObject.method convert it to a weak closure.

let c2: weak (CLOSURETYPE)? = someObject.method Let the compiler do the job for 
us.

The latter would be great for APIs to avoid the prefix.

.subscribe(onNext: self.bar) weak is inferred and can be omitted



-- 
Adrian Zubarev
Sent with Airmail

Am 10. Juni 2017 um 21:09:28, Matthew Johnson ([email protected]) schrieb:

Hi Adrian, this is pretty similar to the Guarded Closures proposal I drafted in 
February.  This proposal needs a revision incorporating discussion feedback and 
some new ideas.  If you’re interested, here’s a link to the original discussion 
thread: 
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170213/032478.html.

On Jun 10, 2017, at 12:29 PM, Adrian Zubarev via swift-evolution 
<[email protected]> wrote:

Hello Evolution,

I’d like to pitch a new idea and see where it would go. Recently I tapped into 
a small trap and just now realized that even that non-escaping should have been 
the default for closures (SE–0103) there is an exception for that. Apparently 
generics don’t follow that rule and a closure like 

Optional<() -> Void> or simply (() -> Void)?

is still escaping by default. But that was the half of the story yet. As we all 
know and “love” reference lists inside closures, methods don’t have any and we 
have to wrap method calls into a weak referenced closure 

{ [weak self] in self.foo() }

to avoid strong reference cycles. Maybe you already guess it, I accidentally 
didn’t and tapped into the land of strong reference cycles yet again on my 
journey.

I’d like to pitch a new way, more like a new type behavior, for closures on how 
they could be used differently in order to avoid strong reference cycles but 
also providing the ability to use methods without any need to wrap them.

Here is a simple code snippet using RxSwift, which will recreate my issue:

import RxSwift

let test = PublishSubject<Void>()

class A {

    let disposeBag = DisposeBag()

    func foo() {
        test.asObservable()
            .subscribe(onNext: self.bar) // The issue is here
            .disposed(by: self.disposeBag)
    }

    func bar() { print("works") }
}

let a = A()
a.foo()

test.onNext(()) // Testing if it works
test.onCompleted() // Some RxSwift stuff
In this case by passing directly the method self.bar we’re capturing self, 
which in this situation isn’t our intention at all. To avoid this issue we can 
simply wrap the method call into closure:

.subscribe(onNext: { [unowned self] in self.bar() })

(It’s safe to make it unowned because the dispose bag is a member of self.)

What if we had the ability for weak or unowned closures? By that I don’t mean 
weak/unowned references to the closures themselves, because they are also 
reference types, but an invalidation behavior for the whole closure based on 
the _captured_ references. For instance:

let closure1: weak (() -> Void)? = { self.doWhatever() }

let closure2: weak (() -> Void)? = self.doWhatever

If one would now try to call the closure, first it will check if all the 
captured objects are still available or not, if not the whole closure in this 
case will simply become nil and won’t execute. In case of unowned closures it 
will trap. Furthermore it will support the general meaning of weak/unowned and 
will not increase the reference counter for *captured objects*.

As you have already noticed, in this case the convention is slightly different 
because we must carry the behavior directly with the type.

func subscribe(onNext: weak ((Swift.E) -> Void)?)

If the way of my thinking is correct this idea _could maybe_ fade out the very 
common [weak self] in guard let strongSelf = self … pattern. 

I personally cannot tell all the technical difficulties this idea might have, 
but that’s what the evolution list is for, to collaboratively flesh out the 
ideas if they are worth it.

If something like this could be possible it’s probably worth noting that we 
might also be able to introduce something like @autoclosure(weak/unowned) to 
Swift for consistency.




-- 
Adrian Zubarev
Sent with Airmail

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to