MOTIVATION:

As per the current situation, there is a pitfall when writing asynchronous APIs 
that does not occur when writing synchronous APIs. Consider the following 
synchronous API:

func doSomething() -> SomeEnum {
        if aCondition {
                if bCondition {
                        return .Foo
                } else {
                        return .Bar
                }
        } else {
                if cCondition {
                        return .Baz
                }
        }
}

The compiler will give an error here, since if both aCondition and cCondition 
are false, the function will not return anything.

However, consider the equivalent async API:

func doSomething(completionHandler: (SomeEnum) -> ()) {
        dispatch_async(someQueue) {
                if aCondition {
                        if bCondition {
                                completionHandler(.Foo)
                        } else {
                                completionHandler(.Bar)
                        }
                } else {
                        if cCondition {
                                completionHandler(.Baz)
                        }
                }
        }
}

Whoops, now the function can return without ever firing its completion handler, 
and the problem might not be discovered until runtime (and, depending on the 
complexity of the function, may be hard to find).

PROPOSED SOLUTION:

Add a @required attribute that can be applied to closure arguments. This 
attribute simply states that the given closure will always be eventually 
called, and the compiler can enforce this.

DETAILED DESIGN:

- The @required attribute states in our API contract that a given closure 
*must* be called at some point after the function is called.

- Standard API calls like dispatch_async that contractually promise to execute 
a closure or block get @required added to their signatures.

- When the compiler sees a @required closure in a function declaration, it 
checks to make sure that every execution path either calls the closure at some 
point, or sends a @required closure to another API that eventually ends up 
calling the closure.

- If there’s a way for a @required closure not to be called, the compiler emits 
an error letting the developer know about the bug in his/her code.

IMPACT ON EXISTING CODE:

None. This is purely additive.

ALTERNATIVES CONSIDERED:

I got nothin’.

Charles

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

Reply via email to