Proposal: Syntax sugar for cps or async functions similar to the "do try catch" for error handling


(Roy Fu) #1

Hi all,

Similar to the syntax ‘do try catch throw’ and ’throws’ for error handling, I propose another syntax for handling CPS functions or async call backs:

func someFutureWrappedFunc(input: Int) future-> String{
    doSomeStaffInBackground{ (result:String) in
        fulfil result
    }
}

do{
    let resultX = perform someFutureWrappedFunc(param)
    let resultY = perform anotherFutureWrappedFunc(resultX)
    let final = resultX + resultY + perform justAnotherFutureWrappedFunc(resultX)
    self.someLabel.text = final
} timeout let context {
    //maybe some additional information
}

the reason for this proposal is for the importance of async models in modern application architectures, and avoid such pyramids:

doSomeStaffInBackground { (resultX) -> Void in
    
    doSomeOtherStaff { (resultY) -> Void in
        
        if resultY.someCondition(resultX) {
            
            evenMakesItMadness(resultY) { (final) -> Void in
                
                //finally
            }
        }
    }
}

For more context comparing this async syntax to the ‘do try catch’:

do try catch:
enum Result<T> {
    case Success(T)
    case Failure(ErrorType)
}

func flatMap<T,U> (result:Result<T>, f:T->Result<U>) -> Result<U>{
    switch result{
    case .Success(let v): return f(v)
    case .Failure(let e): return .Failure(e)
    }
}

func wrap1<T,U>(f:T throws-> U) -> T->Result<U> {
    return {
        do{
            return try .Success(f($0))
        }catch let e{
            return .Failure(e)
        }
    }
}

func wrap2<T,U>(f:T -> Result<U>) -> T throws-> U{
    return{
        switch f($0){
        case .Success(let v): return v
        case .Failure(let e): throw e
        }
    }
}

async:

func flatMap<T,U> (async: (T -> Void) -> Void, f:T -> (U->Void) -> Void) -> (U -> Void) -> Void {
    return{ cont in
        async{ f($0)(cont) }
    }
}

func wrap1<T,U>(f:T future-> U) -> T->(U->Void)->Void {
    return {input in
        {cont in
            do{
                cont(perform f(input))
            }catch _{

            }
        }
    }
}

func wrap2<T,U>(f:T -> (U->Void)->Void) -> T future-> U{
    return{
        f(input)({
            fulfil $0
        })
    }
}


(Chris Lattner) #2

Hi all,

Similar to the syntax ‘do try catch throw’ and ’throws’ for error handling, I propose another syntax for handling CPS functions or async call backs:

We are all very interested in doing things along these lines, but need to keep Swift 3 relatively focused to achieve our goals. Please bring this idea back up as work on Swift 3 is winding down, for consideration in Swift 4.

-Chris

···

On Dec 6, 2015, at 1:21 AM, Roy Fu via swift-evolution <swift-evolution@swift.org> wrote:

func someFutureWrappedFunc(input: Int) future-> String{
    doSomeStaffInBackground{ (result:String) in
        fulfil result
    }
}

do{
    let resultX = perform someFutureWrappedFunc(param)
    let resultY = perform anotherFutureWrappedFunc(resultX)
    let final = resultX + resultY + perform justAnotherFutureWrappedFunc(resultX)
    self.someLabel.text = final
} timeout let context {
    //maybe some additional information
}

the reason for this proposal is for the importance of async models in modern application architectures, and avoid such pyramids:

doSomeStaffInBackground { (resultX) -> Void in
    
    doSomeOtherStaff { (resultY) -> Void in
        
        if resultY.someCondition(resultX) {
            
            evenMakesItMadness(resultY) { (final) -> Void in
                
                //finally
            }
        }
    }
}

For more context comparing this async syntax to the ‘do try catch’:

do try catch:
enum Result<T> {
    case Success(T)
    case Failure(ErrorType)
}

func flatMap<T,U> (result:Result<T>, f:T->Result<U>) -> Result<U>{
    switch result{
    case .Success(let v): return f(v)
    case .Failure(let e): return .Failure(e)
    }
}

func wrap1<T,U>(f:T throws-> U) -> T->Result<U> {
    return {
        do{
            return try .Success(f($0))
        }catch let e{
            return .Failure(e)
        }
    }
}

func wrap2<T,U>(f:T -> Result<U>) -> T throws-> U{
    return{
        switch f($0){
        case .Success(let v): return v
        case .Failure(let e): throw e
        }
    }
}

async:

func flatMap<T,U> (async: (T -> Void) -> Void, f:T -> (U->Void) -> Void) -> (U -> Void) -> Void {
    return{ cont in
        async{ f($0)(cont) }
    }
}

func wrap1<T,U>(f:T future-> U) -> T->(U->Void)->Void {
    return {input in
        {cont in
            do{
                cont(perform f(input))
            }catch _{

            }
        }
    }
}

func wrap2<T,U>(f:T -> (U->Void)->Void) -> T future-> U{
    return{
        f(input)({
            fulfil $0
        })
    }
}

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Thorsten Seitz) #3

Hi Roy,

I’d prefer if such special syntax would not be reserved for just async computations but used for monadic computations in general (with the async case just being a monad implementation).

-Thorsten

···

Am 06.12.2015 um 10:21 schrieb Roy Fu via swift-evolution <swift-evolution@swift.org>:

Hi all,

Similar to the syntax ‘do try catch throw’ and ’throws’ for error handling, I propose another syntax for handling CPS functions or async call backs:

func someFutureWrappedFunc(input: Int) future-> String{
    doSomeStaffInBackground{ (result:String) in
        fulfil result
    }
}

do{
    let resultX = perform someFutureWrappedFunc(param)
    let resultY = perform anotherFutureWrappedFunc(resultX)
    let final = resultX + resultY + perform justAnotherFutureWrappedFunc(resultX)
    self.someLabel.text = final
} timeout let context {
    //maybe some additional information
}

the reason for this proposal is for the importance of async models in modern application architectures, and avoid such pyramids:

doSomeStaffInBackground { (resultX) -> Void in
    
    doSomeOtherStaff { (resultY) -> Void in
        
        if resultY.someCondition(resultX) {
            
            evenMakesItMadness(resultY) { (final) -> Void in
                
                //finally
            }
        }
    }
}

For more context comparing this async syntax to the ‘do try catch’:

do try catch:
enum Result<T> {
    case Success(T)
    case Failure(ErrorType)
}

func flatMap<T,U> (result:Result<T>, f:T->Result<U>) -> Result<U>{
    switch result{
    case .Success(let v): return f(v)
    case .Failure(let e): return .Failure(e)
    }
}

func wrap1<T,U>(f:T throws-> U) -> T->Result<U> {
    return {
        do{
            return try .Success(f($0))
        }catch let e{
            return .Failure(e)
        }
    }
}

func wrap2<T,U>(f:T -> Result<U>) -> T throws-> U{
    return{
        switch f($0){
        case .Success(let v): return v
        case .Failure(let e): throw e
        }
    }
}

async:

func flatMap<T,U> (async: (T -> Void) -> Void, f:T -> (U->Void) -> Void) -> (U -> Void) -> Void {
    return{ cont in
        async{ f($0)(cont) }
    }
}

func wrap1<T,U>(f:T future-> U) -> T->(U->Void)->Void {
    return {input in
        {cont in
            do{
                cont(perform f(input))
            }catch _{

            }
        }
    }
}

func wrap2<T,U>(f:T -> (U->Void)->Void) -> T future-> U{
    return{
        f(input)({
            fulfil $0
        })
    }
}

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Roy Fu) #4

I personally do prefer that too, but, it's still not that clear for the attitude of core team on introducing too much functional paradigms. More importantly we had to consider if this would add on learning curve for new programmers.

···

On Dec 7, 2015, at 12:36 AM, Thorsten Seitz <thorsten.seitz@web.de> wrote:

Hi Roy,

I’d prefer if such special syntax would not be reserved for just async computations but used for monadic computations in general (with the async case just being a monad implementation).

-Thorsten

Am 06.12.2015 um 10:21 schrieb Roy Fu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

Hi all,

Similar to the syntax ‘do try catch throw’ and ’throws’ for error handling, I propose another syntax for handling CPS functions or async call backs:

func someFutureWrappedFunc(input: Int) future-> String{
    doSomeStaffInBackground{ (result:String) in
        fulfil result
    }
}

do{
    let resultX = perform someFutureWrappedFunc(param)
    let resultY = perform anotherFutureWrappedFunc(resultX)
    let final = resultX + resultY + perform justAnotherFutureWrappedFunc(resultX)
    self.someLabel.text = final
} timeout let context {
    //maybe some additional information
}

the reason for this proposal is for the importance of async models in modern application architectures, and avoid such pyramids:

doSomeStaffInBackground { (resultX) -> Void in
    
    doSomeOtherStaff { (resultY) -> Void in
        
        if resultY.someCondition(resultX) {
            
            evenMakesItMadness(resultY) { (final) -> Void in
                
                //finally
            }
        }
    }
}

For more context comparing this async syntax to the ‘do try catch’:

do try catch:
enum Result<T> {
    case Success(T)
    case Failure(ErrorType)
}

func flatMap<T,U> (result:Result<T>, f:T->Result<U>) -> Result<U>{
    switch result{
    case .Success(let v): return f(v)
    case .Failure(let e): return .Failure(e)
    }
}

func wrap1<T,U>(f:T throws-> U) -> T->Result<U> {
    return {
        do{
            return try .Success(f($0))
        }catch let e{
            return .Failure(e)
        }
    }
}

func wrap2<T,U>(f:T -> Result<U>) -> T throws-> U{
    return{
        switch f($0){
        case .Success(let v): return v
        case .Failure(let e): throw e
        }
    }
}

async:

func flatMap<T,U> (async: (T -> Void) -> Void, f:T -> (U->Void) -> Void) -> (U -> Void) -> Void {
    return{ cont in
        async{ f($0)(cont) }
    }
}

func wrap1<T,U>(f:T future-> U) -> T->(U->Void)->Void {
    return {input in
        {cont in
            do{
                cont(perform f(input))
            }catch _{

            }
        }
    }
}

func wrap2<T,U>(f:T -> (U->Void)->Void) -> T future-> U{
    return{
        f(input)({
            fulfil $0
        })
    }
}

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution