Skip to content

Instantly share code, notes, and snippets.

@marcoconti83
Created October 29, 2015 23:46
Show Gist options
  • Select an option

  • Save marcoconti83/0e62e5986153334b9934 to your computer and use it in GitHub Desktop.

Select an option

Save marcoconti83/0e62e5986153334b9934 to your computer and use it in GitHub Desktop.
Guard-catch in swift?
/**
# QUESTION
Is there a way to combine `guard` and `try-catch`, so that we can
exploit the `guard let` to have a immutable value, but have an early
return in case of errors?
*/
import Foundation
/// Very obscure errors
enum ObscureError : ErrorType {
case DisturbanceInTheForce
case TimeDilationAnomaly
}
enum ComputationError : ErrorType {
case Error(_: String)
}
/// A very unstable function
func blackBox() throws -> UInt32 {
guard arc4random_uniform(6) != 3 else { throw ObscureError.DisturbanceInTheForce }
guard arc4random_uniform(6) != 1 else { throw ObscureError.TimeDilationAnomaly }
return arc4random_uniform(6)
}
/**
# SOLUTION 1
Use `var`s, and assign to them them inside a `do-catch`
## PROS:
- We can distinguish between `DisturbanceInTheForce` and `TimeDilationAnomaly`
## CONS:
- `foo` has to be a `var` even if it should be a `let`
*/
func compute1() throws {
var foo1 : UInt32
var foo2 : UInt32
do {
foo1 = try blackBox()
}
catch ObscureError.DisturbanceInTheForce {
throw ComputationError.Error("a")
}
catch ObscureError.TimeDilationAnomaly {
throw ComputationError.Error("b")
}
do {
foo2 = try blackBox()
}
catch ObscureError.DisturbanceInTheForce {
throw ComputationError.Error("c")
}
catch ObscureError.TimeDilationAnomaly {
throw ComputationError.Error("d")
}
// ... some calculation that uses foo1 and foo2 ...
print("\(foo1+foo2)")
}
/**
# SOLUTION 2
Use `let` inside nested `do-catch`es
## PROS:
- We can distinguish between `DisturbanceInTheForce` and `TimeDilationAnomaly`
- `foo` is a let
## CONS:
- Readability issue
- Quickly degenerates into a Pyramid of Doom
*/
func compute2() throws {
do {
let foo1 = try blackBox()
do {
let foo2 = try blackBox()
// ... some calculation that uses foo1 and foo2 ...
print("\(foo1+foo2)")
}
catch ObscureError.DisturbanceInTheForce {
throw ComputationError.Error("c")
}
catch ObscureError.TimeDilationAnomaly {
throw ComputationError.Error("d")
}
}
catch ObscureError.DisturbanceInTheForce {
throw ComputationError.Error("a")
}
catch {
throw ComputationError.Error("b")
}
}
/**
# SOLUTION 3
Use a `guard` and a optional `try` to d
PROS:
- Extremely readable and concise
- `foo` is a `let`
CONS:
- Can't distinguish between errors. Is it a `DisturbanceInTheForce` or a `TimeDilationAnomaly`?
*/
func compute3() throws {
guard let foo1 = try? blackBox() else { throw ComputationError.Error("a or b") }
guard let foo2 = try? blackBox() else { throw ComputationError.Error("c or d") }
// ... some calculation that uses foo1 and foo2 ...
print("\(foo1+foo2)")
}
/**
# SOLUTION 4
Hypothetical `guard-catch` construct
PROS:
- Readable
- `foo` is a `let`
CONS:
- Not supported in Swift :)
*/
/*
func compute4() throws {
guard let foo1 = try blackBox()
catch ObscureError.DisturbanceInTheForce {
ComputationError.Error("a")
}
catch {
ComputationError.Error("b")
}
guard let foo2 = try blackBox()
catch ObscureError.DisturbanceInTheForce {
ComputationError.Error("c")
}
catch {
ComputationError.Error("d")
}
// ... some calculation that uses foo1 and foo2 ...
print("\(foo1+foo2)")
}
*/
Copy link

ghost commented Feb 20, 2017

@WinterArch
Copy link

SOLUTION 1 can be:

let foo1: UInt32?
let foo2: UInt32?
do {
// binding it here...
} catch {
// initialize A nil here ...
}
do ... catch ... so on...

It really can be LET, tediously.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment