If weak closures ever become a thing, I do think that the implicit strong promotion of the closure's captures should never happen and instead, the closure should be manually optional-unwrapped before it's called, so that the existing safety guarantees of weak object references would persist.
> On Jun 10, 2017, at 11:04 PM, Adrian Zubarev > <[email protected]> wrote: > > Just a few more replies from John McCall: > > You want to invalidate the closure value based on whether any of its captures > have been invalidated. > > It’s an interesting idea, but it’s quite complex because an invalidatable > closure is definitely a different sort of thing from a normal one. > > So like you say, it would need to be tracked in the type, which is not the > language model we otherwise use for closures. Er, for weak/unowned, I mean. > > The behavior for unowned is not too different from the current behavior, so > it’s really mostly about weak. > > I guess the captured reference becomes strong immediately, protecting against > it going away during the closure. > > But unowned is conventionally used in cases where that isn’t going to happen > anyway. > > The semantics of testing a “weak closure” are not obvious. Always must be > wrapped in optional, unwrapping it gives a value of non-weak type? > > Totally different from normal optional behavior on values, but I guess it > works. > > > > -- > Adrian Zubarev > Sent with Airmail > > Am 10. Juni 2017 um 21:58:21, Adrian Zubarev ([email protected] > <mailto:[email protected]>) schrieb: > >> Well I simply reused the existing keywords as part of the closure type to >> demonstrate the idea here as easy as possible. >> >> About the _true_ weak/unowned closures. First I asked John McCall on twitter >> about this whole idea. Here is his reply about the _true_ weak closures: >> >> You mean a weak reference to a closure? No, I don’t think we’d ever want to >> assign closure values enough identity to give that meaning. >> I get it, that it might be not quite obvious or even confusing why >> weak/unowned can be applied on a type and on a variable. However weak is >> always an Optional or an IUO where unowned is non-optional. >> >> Just my personal thoughts: Could we potentially align weak/unowned with >> inout and make it type decoration? (This would be a breaking change.) >> >> >> >> -- >> Adrian Zubarev >> Sent with Airmail >> >> Am 10. Juni 2017 um 21:44:41, Gor Gyolchanyan ([email protected] >> <mailto:[email protected]>) schrieb: >> >>> I don't think it's a good idea to make the `weak`-ness of the closure part >>> of the type system. >>> The current approach to `weak/unowned` is that it's a storage class that >>> applies to the variable, not the value. >>> This makes sense because you don't *use* a weak reference, you only *store* >>> it weakly. >>> I think this behavior has to stay the same with the addition of closures >>> (being the other reference type along classes) would be eligible for >>> storing by `weak/unowned` reference. >>> >>>> On Jun 10, 2017, at 10:39 PM, Adrian Zubarev via swift-evolution >>>> <[email protected] <mailto:[email protected]>> wrote: >>>> >>>> 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] >>>> <mailto:[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 >>>>> >>>>> <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] <mailto:[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] <mailto:[email protected]> >>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution> >>>>> >>>> >>>> >>>> _______________________________________________ >>>> swift-evolution mailing list >>>> [email protected] <mailto:[email protected]> >>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>> <https://lists.swift.org/mailman/listinfo/swift-evolution> >>> >> > >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
