> Am 06.06.2016 um 22:30 schrieb Charles Srstka via swift-evolution 
> <[email protected]>:
> 
> On Jun 6, 2016, at 2:49 PM, Michael Peternell <[email protected]> 
> wrote:
>> 
>> That's really hard to answer in the general case. I think real proposals 
>> should contain concrete, realistic examples that show the benefit of the 
>> proposal. It's really hard to argue against a proposal if there is no such 
>> example. User feedback from a sheet is one of the few examples where 
>> asynchronous programming makes sense: But I cannot see how a `@required` 
>> annotation would be useful in that setting.
> 
> Quick-n-dirty example, written in Mail. How would you make this synchronous?

Yes, ok...

Well, I cannot easily make everything synchronous. I just can change it in a 
way that makes a `@required` attribute "optional" ;)

import Foundation

enum Result<T> {
    case success(T)
    case error(ErrorType)
}

enum MyError: ErrorType {
    case unknownError
    case corruptData
    case badStatusCode(Int)
}

struct SomeThing {
    init?(data: NSData) {
        ...
    }
}

func getSomethingFromTheNetwork(url: NSURL, completionHandler: 
(Result<SomeThing>) -> ()) { 
    func toSomeThing(data: NSData?, response: NSURLResponse?, error: NSError?) 
-> Result<SomeThing> {
        if let error = error {
            return .error(error)
        }

        if let httpResponse = response as? NSHTTPURLResponse {
            let statusCode = httpResponse.statusCode
            
            if statusCode < 200 || statusCode >= 300 {
                return .error(MyError.badStatusCode(statusCode))
            }
        }
    
        guard let data = data else {
            return .error(MyError.unknownError)
        }

        guard let something = SomeThing(data: data) else {
            return .error(MyError.corruptData)
        }

        return .success(something)
    }
    let task = NSURLSession.sharedSession().dataTaskWithURL(url) { data, 
response, error in
        completionHandler(toSomething(data, response, error))
    }
    
    task.resume()
}

With a semaphore, I can also make it synchronous. Not sure if this is a good 
idea though... If the API is already asynchronous, it's probably better to use 
it that way.

/// Should not be called from the main thread
func getSomethingFromTheNetworkSync(url: NSURL) -> Result<SomeThing> { 
    func toSomeThing(data: NSData?, response: NSURLResponse?, error: NSError?) 
-> Result<SomeThing> {
        if let error = error {
            return .error(error)
        }

        if let httpResponse = response as? NSHTTPURLResponse {
            let statusCode = httpResponse.statusCode
            
            if statusCode < 200 || statusCode >= 300 {
                return .error(MyError.badStatusCode(statusCode))
            }
        }
    
        guard let data = data else {
            return .error(MyError.unknownError)
        }

        guard let something = SomeThing(data: data) else {
            return .error(MyError.corruptData)
        }

        return .success(something)
    }
    let sema = dispatch_semaphore_create(0)
    var result = Result<Something>?
    let task = NSURLSession.sharedSession().dataTaskWithURL(url) { data, 
response, error in
        result = toSomething(data, response, error)
        dispatch_semaphore_signal(sema)
    }
    
    task.resume()
    dispatch_semaphore_wait(sema)
    return result!
}

The other example can be transformed in the same way..

-Michael

> 
> import Foundation
> 
> enum Result<T> {
>       case success(T)
>       case error(ErrorType)
> }
> 
> enum MyError: ErrorType {
>       case unknownError
>       case corruptData
>       case badStatusCode(Int)
> }
> 
> struct SomeThing {
>       init?(data: NSData) {
>               ...
>       }
> }
> 
> func getSomethingFromTheNetwork(url: NSURL, completionHandler: 
> (Result<SomeThing>) -> ()) {   
>       let task = NSURLSession.sharedSession().dataTaskWithURL(url) { data, 
> response, error in
>               if let error = error {
>                       completionHandler(.error(error))
>                       return
>               }
> 
>               if let httpResponse = response as? NSHTTPURLResponse {
>                       let statusCode = httpResponse.statusCode
>                       
>                       if statusCode < 200 || statusCode >= 300 {
>                               
> completionHandler(.error(MyError.badStatusCode(statusCode)))
>                               return
>                       }
>               }
>       
>               guard let data = data else {
>                       completionHandler(.error(MyError.unknownError))
>                       return
>               }
> 
>               guard let something = SomeThing(data: data) else {
>                       completionHandler(.error(MyError.corruptData))
>                       return
>               }
> 
>               completionHandler(.success(something))
>       }
>       
>       task.resume()
> }
> 
> (disclaimer: yes, we’d probably have to improve the API for NSURLSession a 
> bit here for @required to be useful.)
> 
> How would you make this synchronous:
> 
> func getSomethingFromAnotherTask(completionHandler: (Result<SomeThing>) -> 
> ()) {
>       let message = ...
> 
>       xpc_send_message_with_reply(self.connection, message, 
> self.dispatchQueue) { reply in
>               do {
>                       let something = try 
> self.turnReplyIntoSomethingSomehow(reply)
>               
>                       completionHandler(.success(something))
>               } catch {
>                       completionHandler(.error(error))
>               }
>       }
> }
> 
> Or this:
> 
> func doSomethingThatNeedsUserInput(completionHandler: (Bool) -> ()) {
>       let alert = NSAlert()
> 
>       alert.messageText = “Should we continue?”
>       alert.addButtonWithTitle(“Continue”)
>       alert.addButtonWithTitle(“Cancel”)
> 
>       alert.beginSheetModalForWindow(someWindow) { response in
>               if response == NSAlertFirstButtonReturn {
>                       completionHandler(true)
>               }
> 
>               // uh oh, I forgot to test for other conditions, and now the 
> completion handler won’t be called if the user clicked “Cancel”.
>               // Too bad the compiler couldn’t warn me about it.
>       }
> }
> 
> There are some tasks which synchronous programming is simply not well-suited 
> for.
> 
> Charles
> 
> _______________________________________________
> 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