Also the Scala approach already works quite nicely in Swift 4 in case anyone 
was curious:

enum Try<T> {
    case success(T)
    case failure(Error)

    init(_ f: @autoclosure () throws -> T) {
        do {
            self = .success(try f())
        } catch {
            self = .failure(error)
        }
    }
}


let handlerDisposableTry = Try(try startHandler(observer))

switch handlerDisposableTry {
case .success(let x):
    x?.dispose()
case .failure(let error):
    print(error)
}

It’s just a touch awkward with the double try.

Tyler


> On Oct 7, 2017, at 10:42 PM, Tyler Cloutier <cloutierty...@aol.com> wrote:
> 
>> try startHandler(observer) catch {
>>     observer.sendFailed(error)
>> }
> 
> 
> Technically the above doesn’t make sense. Please disregard.
> 
>> On Oct 7, 2017, at 10:35 PM, Tyler Cloutier <cloutierty...@aol.com 
>> <mailto:cloutierty...@aol.com>> wrote:
>> 
>> Has there been any progress on this? I came here to propose this but came 
>> upon this thread first.
>> 
>> This proposal goes way beyond sugar. I find myself constantly in the 
>> following situation:
>> 
>>         let observer = Observer(with: CircuitBreaker(holding: self))
>>         do {
>>             let handlerDisposable = try startHandler(observer)
>>         } catch {
>>             observer.sendFailed(error)
>>         }
>> 
>>         cancelDisposable = ActionDisposable {
>>             observer.sendInterrupted()
>>             handlerDisposable?.dispose() // Error!!!! handlerDisposable is 
>> not defined here
>>         }
>> 
>> It’s not as simple as putting it all in the do block because then I’ll be 
>> catching errors I might not want to catch! (In this case if the initializer 
>> of ActionDisposable was capable of throwing.)
>> 
>> This is my frustration with every language that has this style of error 
>> handling. FWIW, Scala is the only language that I have seen with this style 
>> of error handling that solves this problem. The built-in type `Try` combined 
>> with pattern matching fixes this issue of over extending the catch area. 
>> Which is kinda nifty and also bridges the functional gap as well.
>> 
>> object Try {
>>      /** Constructs a `Try` using the by-name parameter.  This
>>      * method will ensure any non-fatal exception is caught and a
>>     * `Failure` object is returned.
>>     def apply[T](r: => T): Try[T] =
>>       try Success(r) catch {
>>         case NonFatal(e) => Failure(e)
>>       }
>>     }
>> }
>> 
>> It also would make
>> 
>> try startHandler(observer) catch {
>>     observer.sendFailed(error)
>> }
>> 
>> an obvious extension which to me makes sense since it’s just treating the 
>> one function call expression as it’s own implicit do block.
>> 
>> Tyler
>> 
>> 
>> 
>>> On Jul 11, 2017, at 10:31 AM, Christopher Kornher via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> 
>>> 
>>> 
>>> Begin forwarded message:
>>> 
>>> From: Christopher Kornher <ckorn...@me.com <mailto:ckorn...@me.com>>
>>> Subject: Re: [swift-evolution] [Pitch] Guard/Catch
>>> Date: July 10, 2017 at 5:10:15 PM MDT
>>> To: Elviro Rocca <retired.hunter.dj...@gmail.com 
>>> <mailto:retired.hunter.dj...@gmail.com>>
>>> 
>>> This messages was modified from the original accidentally sent out 
>>> privately, earlier.
>>> 
>>> FYI this works today in Xcode 9.0 beta 2 playgrounds:
>>> 
>>> ```
>>> class X {
>>>     init() throws {}
>>> 
>>>     func foo() {
>>>         print( "Things succeeded" )
>>>     }
>>> }
>>> 
>>> func bar() throws -> X  { return try X() }
>>> 
>>> 
>>> func f()
>>> {
>>>     guard let x1:X = try? X(), let x2:X = try? bar() else {
>>>         print( "Things failed ")
>>>         return
>>>     }
>>> 
>>>     x1.foo()
>>>     x2.foo()
>>> }
>>> 
>>> f()        // works
>>> ```
>>> 
>>> 
>>> Most of the examples of this proposed feature don’t handle the exceptions 
>>> other than to perform an early return. 
>>> So, without handing exceptions,  the only unhandled case is a non-returning 
>>> throwing function or init:
>>>  
>>> ```
>>> class X {
>>>     init() throws {}
>>> 
>>>     func foo() {
>>>         print( "Things succeeded" )
>>>     }
>>> }
>>> 
>>> func bar() throws{ let _ =  try X() }
>>> 
>>> 
>>> func f()
>>> {
>>>     do {
>>>         try bar()
>>>     } catch {
>>>         return
>>>     }
>>> 
>>>     guard let x:X = try? X() else {
>>>         print( "Things failed ")
>>>         return
>>>     }
>>> 
>>>     x.foo()
>>> }
>>> 
>>> f()        // works
>>> ```
>>> 
>>> Having to call a throwing, Void method before performing the rest of a 
>>> non-throwing function (or closure ) seems like an edge case to me. Perhaps 
>>> I am just biased by my experience. I have not created or used many throwing 
>>> initializers and certainly none in guard statements, and if they were in 
>>> guard statements, the need to handle exceptions differently from any other 
>>> guard failure seems ever more unlikely.
>>> 
>>> I don’t think that the small rightward drift of exception handling is 
>>> onerous. It is hardly like the “pyramid of doom” that ```guard``` was 
>>> created to fix.
>>> 
>>> ```
>>> func f( y:Int? = nil )
>>> {
>>>     do {
>>>         try bar()
>>>         let x:X = try X()
>>>         
>>>         guard let y = y else {
>>>             print( "No y")
>>>             return
>>>         }
>>>         
>>>         x.foo()
>>>         print( "y=\(y)")
>>>     } catch {
>>>         // Handle some exceptions.
>>>         return
>>>     }
>>> }
>>> ```
>>> 
>>> On Jul 10, 2017, at 1:45 AM, Elviro Rocca via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> 
>>> This is not a sugar proposal, in the same way as "guard" is not syntactic 
>>> sugar, because it requires exiting the scope on the else branch, adding 
>>> expressive power and safety to the call: also, the sugary part is pretty 
>>> important because it avoids nested parentheses and very clearly states that 
>>> if the guard condition is not fulfilled, the execution will not reach the 
>>> next lines of code. Guard is useful to push the programmer to at least 
>>> consider an early return instead of branching code paths, to achieve better 
>>> clarity, readability and lower complexity, and I suspect is one of the best 
>>> Swift features for many people.
>>> 
>>> Also, the case that the proposal aims to cover is not an edge case at all 
>>> for a lot of people, including me. Rethrowing an error is something that I 
>>> almost never do, and I consider the "umbrella" do/catch at the top of the 
>>> call stack an anti-pattern, but I understand that many people like it and 
>>> I'm not arguing against it. I am arguing in favor of having options and not 
>>> pushing a particular style onto programmers, and for my (and many people's) 
>>> style, a guard/catch with forced return is an excellent idea. In fact you 
>>> seem to agree on the necessity of some kind of forced-returnish catch but 
>>> your elaborations don't seem (to me) much better than the proposal itself.
>>> 
>>> Dave DeLong raised the point of weird behavior in the case of a function 
>>> like:
>>> 
>>> 
>>> func doSomething() throws → Result? { … }
>>> 
>>> 
>>> In this case, what would the type of x be?
>>> 
>>> 
>>> guard let x = try doSomething() catch { /// handle and return }
>>> 
>>> 
>>> Simple, it would be Optional<Result>. I don't find this confusing at all, 
>>> and if the idea that just by seeing "guard let" we should expect a 
>>> non-Optional is somehow diffused, I think it's better to eradicate it.
>>> 
>>> First of all, if I'm returning an optional from a throwing function, it's 
>>> probably the case that I want the Optional to be there in the returned 
>>> value: the only reason why I would consider doing that is if the semantics 
>>> of Optional are pretty meaningful in that case. For example, when parsing a 
>>> JSON in which I expect a String or null to be at a certain key:
>>> 
>>> 
>>> extension String: Error {}
>>> 
>>> func parseString(in dict: [String:Any], at key: String) throws -> String? {
>>>     guard let x = dict[key] else { throw "No value found at '\(key)' in 
>>> \(dict)" }
>>>     if let x = x as? String { return x }
>>>     if let x = x as? NSNull { return nil }
>>>     throw "Value at '\(key)' in \(dict) is not 'string' or 'null"
>>> }
>>> 
>>> 
>>> Thus, if I'm returning an Optional from a throwing function it means that I 
>>> want to clearly distinguish the two cases, so they shouldn't be collapsed 
>>> in a single call:
>>> 
>>> 
>>> guard let x = try doSomething() catch { /// handle and return }
>>> guard let x = x else { /// handle and return }
>>> 
>>> 
>>> Also, if a function returns something like "Int??", a guard-let (or if-let) 
>>> on the returned value of that function will still bind an "Int?", thus 
>>> unwrapping only "one level" of optional. If-let and guard-let, as of today, 
>>> just unwrap a single optional level, an do not guaranteed at all that the 
>>> bound value is not optional.
>>> 
>>> To me guard-let (like if-let) is basically sugar for monadic binding for 
>>> Optionals, with the additional expressivity granted by the forced return. I 
>>> would love to see the same monadic binding structure applied to throwing 
>>> functions.
>>> 
>>> 
>>> 
>>> Elviro
>>> 
>>> 
>>> 
>>> 
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>> Il giorno 09 lug 2017, alle ore 01:16, Christopher Kornher via 
>>>> swift-evolution <swift-evolution@swift.org 
>>>> <mailto:swift-evolution@swift.org>> ha scritto:
>>>> 
>>>> Thanks for you considerate reply. My concern over the proliferation of 
>>>> “sugar proposals” is a general one. This proposal has more merit and 
>>>> general utiliity than many others. I have never used a throwing function 
>>>> in a guard statement that was not itself in a throwing function, but I can 
>>>> see that it could possibly be common in some code. Wrapping a guard 
>>>> statement and all the code that uses variables set in the guard in a 
>>>> do/catch is sub-optimal.
>>>> 
>>>> 
>>>> All catches don’t have to exit the outer scope, so using guard only 
>>>> handles a subset 
>>>> 
>>>> It think that creating the terse try/catch for simple cases has multiple 
>>>> advantages:
>>>> 
>>>>    1) I think that it addresses your desire for a simple way to use 
>>>> throwing functions easily in guard statements.
>>>> 
>>>>    2) It avoids having to change the guard syntax to accomplish this
>>>> 
>>>>    3) It is useful for handling simple one line try/catch constructs in 
>>>> less space in a way that should not seem too foreign to Swift developers.
>>>>    
>>>>    4) It simplifies code that currently uses nested do/try/catch 
>>>> constructs. Even though this is rare, it introduces significant “rightward 
>>>> drift”.
>>>> 
>>>>    5) It can used to return early from void throwing functions easily. 
>>>> e.g. : 
>>>> 
>>>>    ```
>>>>    ```
>>>>    
>>>>    Multiple void throwing functions would probably be better handled by a 
>>>> do/catch block, but there is no danger of needing values from these 
>>>> functions because there are none:
>>>> 
>>>>    ```
>>>>    ```
>>>> 
>>>>    I did not think of this before, but perhaps we could allow `do` to be 
>>>> replaced with `guard`, thereby allowing values to escape to the outer 
>>>> scope, while still ensuring an early exit:
>>>> 
>>>>    ```
>>>>    ```
>>>> I am not sure that “leaky” braces are a good idea, so perhaps some other 
>>>> character could be used to indicate a non-scope or whatever you want to 
>>>> call it:
>>>> 
>>>>    ```
>>>>    ```
>>>> This would make the language even harder to read, so just using braces is 
>>>> probably a better idea.
>>>> 
>>>> This would change the guard syntax slightly, but is a straightforward 
>>>> extrapolation of do/catch and guard, I think. Of course, this could 
>>>> replace the existing guard syntax entirely and its use of semicolons, if 
>>>> we want to go that far…
>>>> 
>>>> Allowing this syntax only if one of the expressions throws is possibly a 
>>>> good backward-compatible solution that would avoid redundant guard 
>>>> syntaxes.
>>>> 
>>>> Anyway there are lot of possibilities here. We are not forced to extend 
>>>> the guard statement as it exists today. The current guard statement syntax 
>>>> was quite controversial when it was introduced and extending it may not be 
>>>> the best option to do what you want.
>>>> 
>>>> - Chris
>>>> 
>>>> 
>>>> 
>>>> 
>>>> 
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>> On Jul 8, 2017, at 4:16 PM, Benjamin Spratling via swift-evolution 
>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>>> 
>>>>> 
>>>>> 
>>>>> I’ve read your email, but haven’t digested it fully.  One thing I agree 
>>>>> with is that most functions which call throwing functions don’t actually 
>>>>> use a do…catch block, but instead are merely marked “throws” and the 
>>>>> error is propagated back through the stack.  Once I seriously started 
>>>>> coding functions with errors, I realized I almost always wanted my errors 
>>>>> to reach my view-controller or my business logic so I could present 
>>>>> separate UI if a real error occurred, and often my error message depended 
>>>>> on the details of the error instance.
>>>>> 
>>>>> 
>>>>> 
>>>>> I disagree with your conclusion on this point.
>>>>> The “guard” syntax is specifically designed to achieve early return (and 
>>>>> placing code associated with early return at the point where it happens) 
>>>>> and cleanly installing the returned value into the surrounding scope.  So 
>>>>> far it has been used to achieve early return only with optionals, true.  
>>>>> But is that inherent to ‘guard’, or is it merely because that’s the only 
>>>>> way it has been used?  The guard does set variables that are needed in 
>>>>> the body of the function, and that’s exactly why using guard with values 
>>>>> returned from throwing functions makes so much sense, because it does 
>>>>> exactly the same thing in a general sense.  The “do”…”catch” structure is 
>>>>> intentionally designed differently, to place the “happy path” in one 
>>>>> place and place the returns in another place.  I think with guard/else, 
>>>>> we’re seeing developers who can handle less cognitive loading find it 
>>>>> easier to reason about early return than grouping failures after the 
>>>>> happy path.  This proposal hopes to introduce that better language 
>>>>> architecture to the catching of errors.
>>>>>> On Jul 8, 2017, at 4:08 PM, Christopher Kornher <ckorn...@me.com 
>>>>>> <mailto:ckorn...@me.com>> wrote:
>>>>>> 
>>>>>> I am opposed to this proposal because it muddies up the language to 
>>>>>> support what is essentially an edge case. The standard way to exit a 
>>>>>> function early because an exception is thrown is to make the function 
>>>>>> itself throw, if it is part of a larger operation. The addition of a few 
>>>>>> lines of try/catch code is not a great burden and makes the termination 
>>>>>> of an an exception very clear.
>>>>>> `guard` statements are generally used to set variables that are needed 
>>>>>> in the body of a function. Using them to save a few lines of exception 
>>>>>> handing code is a very different use. There is no need to mix two 
>>>>>> relatively clean syntaxes for a few edge cases and increase cognitive 
>>>>>> load one more time, 
>>>>>   guard try foo( ) catch { return }
>>>>>   do {
>>>>>           try fn1()
>>>>>           try fn2()
>>>>>   } catch {
>>>>>           // keep going, return or call a non-returning function, since 
>>>>> throw is already handled by declaring a throwing enclosing function.
>>>>>           // No varibles are needed by the outer block because none are 
>>>>> set
>>>>>           // So it is not clearly a guard-like statement
>>>>>   }        
>>>>>   guard {
>>>>>           try fn1()
>>>>>           try fn2()
>>>>>           let x = fn3()
>>>>>   } catch {
>>>>>           // Must exit
>>>>>   } else {
>>>>>           // Must exit
>>>>>   }        
>>>>>   guard <your favorite character here>
>>>>>           try fn1()
>>>>>           try fn2()
>>>>>           let x = fn3()
>>>>>    <another favorite character here> catch {
>>>>>           // Must exit
>>>>>   } else {
>>>>>           // Must exit
>>>>>   }        
>>>>> 
>>>>> -Ben Spratling
>>>>> 
>>>>> _______________________________________________
>>>>> swift-evolution mailing list
>>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>> 
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> 
> 

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

Reply via email to