[swift-evolution] Guaranteed closure execution

Dany St-Amant dsa.mls at icloud.com
Sun Jan 31 11:54:27 CST 2016


> Le 31 janv. 2016 à 01:17, Félix Cloutier via swift-evolution <swift-evolution at swift.org> a écrit :
> 
> I'd like to pitch this proposal to implement the feature: https://github.com/zneak/swift-evolution/blob/master/proposals/00xx-noescape-once.md <https://github.com/zneak/swift-evolution/blob/master/proposals/00xx-noescape-once.md>
> 
> Rationale for some points:
> 
>> Only one closure parameter can be marked as @noescape(once) in a function signature.
> 
> 
> The attribute doesn't specify the order of execution of the closures, so it could have unintended consequences if closure B depends on closure A but closure B is called first. Given the typical use case (the @noescape(once) closure as a trailing closure), I don't think that it's worth it to invest a lot of effort into coming up with a model to decide (and enforce) which closure has to be called first and what to do if either closure throws or something.
> 
>> it is not required to be executed on a code path that throws;
> 
> 
> It may need to be clarified into "must" or "must not", but I can't think about very good examples supporting either case right now.
> 

What is the implication of this @noescape(once) closure not being call on throws when the caller use try? variation? Looks like the compiler will have to assume that the @escape(once) is both not called and not not called (sorry for the double-negative). For the try!, i think that the compiler could assume that the @escape(none) is called, as the process would crash otherwise anyway on the throw.

    var bad: Bool = true
    enum e: ErrorType {
        case Simple
    }
    func f(@noescape closure: () -> ()) throws {
        if (bad) { throw e.Simple }
        closure()
    }
    let x: Int  // Not initialized
    try? f { x = 1 }
    print(x)    // May still be uninitialized, compiler must generate error
    x = 2       // May have been initialized, compiler must generate error

This should probably be highlighted in the proposal as an intended limitation for the typical usage.
Another special case with try? that people may be unlikely to use, is:

    func g(@noescape closure: () -> ()) throws -> Int {
        if (bad) { throw e.Simple }
        closure()
        return 1
    }
    if let data = try? g({ x = 1 }) {
        print(x) // Guaranteed to be initialized
    }
    print(x)    // May still be uninitialized, compiler must generate error
    x = 2       // May have been initialized, compiler must generate error

Not sure if this case will make the implementation more complex, it is why I’m mentioning it.

Dany
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160131/924e360d/attachment.html>


More information about the swift-evolution mailing list