> On 16 Nov 2016, at 11:06, Nick Keets via swift-evolution
> <[email protected]> wrote:
>
> Hello all, I'm interested in a pattern to return failure, together with an
> error
> to explain why. I think that the "guard let x = x" discussion touched on the
> issue,
> but didn't really go in that direction.
>
> Right now, optional and boolean results work nicely with guards, but you only
> get
> sucess/failure back. For example:
>
> func foo() -> Int?
> func bar() -> Bool
> func baz(Int) -> Int?
>
> guard
> let a = foo(),
> bar(),
> let b = baz(a)
> else {
> // No information about what failed here
> print("Something failed")
> return
> }
>
> I see a lot of enum Result solutions being proposed, but they have the
> fundamental
> problem of not having access to the error inside guards. For example:
>
> enum Result<T> { case sucess(T), error(String) }
>
> func foo() -> Result<Int>
>
> guard case let .success(value) = foo() else {
> // Result is .error but we have no access to the error message here
> return
> }
>
> I think a solution to this problem could be to allow "guard let try"
> statements
> that make the error available inside the else statement. So you could write:
>
> func foo() throws -> Int
> func bar() -> Bool
> func baz(Int) throws -> Int
>
> guard
> let a = try foo(),
> bar(),
> let b = try baz(a)
> else {
> // `error` is available here like in a catch block
> print("Error: \(error.localizedDescription)")
> return
> }
>
> A potential weirdness of this solution is that it appears indistinguishable
> from
> "guard let try?" (already available) if you are not interested in the error.
>
> Thoughts?
I think it comes to a point where you may be expecting too much of guard, when
this is really what a switch or try/catch is for.
One of the purposes of switch is exhaustive handling for enums, so that's the
best way to handle them if you're interested in more than one case. Whereas
try/catch is exactly what you want if you want to, well, catch an error.
However, I wouldn't mind if maybe we could just have an optional catch on guard
statements, like so:
guard let a = try foo(), baz(), let b = try baz(a)
else { return; } // baz() returned false, or foo() or baz()
returned nil
catch(error) { print("Error: \(error.localizedDescription)");
return } // foo() or baz() threw an exception
This would still have the same requirements as a guard's else statement (must
change flow with break, return, throw etc.) but is only triggered in the
exception case. If your guard condition can *only* fail as a result of an
exception then you can omit the else. For example, if you skip the call to
bar(), and foo() and baz(a) can't return nil then the following would be valid:
guard let a = try foo(), let b = baz(a) catch(error) { print("Error:
\(error.localizedDescription)"); return }
The main benefit here being that you get the same kind of in-scope a and b
variables, unlike a try/catch block where they are limited to their own scope
only (or you have to declare them outside which is messy).
I don't see how the enum case could be usefully simplified though, as you'd
need to have pattern matching of some kind to define the error condition you
expect, in which case you might as well just use a switch anyway, whereas a
guard/catch at least eliminates an annoyance of try/catch when dealing with
something that only fails initially._______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution