Update
In swift 1.2 you can do
if let a = optA, let b = optB {
doStuff(a, b)
}
Original answer
In your specific case, you can use optional chaining:
if let b = optionaObj?.a?.b {
// do stuff
}
Now, if you instead need to do something like
if let a = optA {
if let b = optB {
doStuff(a, b)
}
}
you're out of luck, since you can't use optional chaining.
tl; dr
Would you prefer a cool one-liner instead?
doStuff <^> optA <*> optB
Keep reading. For how scaring it might look, this is really powerful and not so crazy to use as it seems.
Fortunately, this is a problem easily solved using a functional programming approach. You can use the Applicative
abstraction and provide an apply
method for composing multiple options together.
Here's an example, taken from http://robots.thoughtbot.com/functional-swift-for-dealing-with-optional-values
First we need a function to apply a function to an optional value only only when it contains something
// this function is usually called fmap, and it's represented by a <$> operator
// in many functional languages, but <$> is not allowed by swift syntax, so we'll
// use <^> instead
infix operator <^> { associativity left }
func <^><A, B>(f: A -> B, a: A?) -> B? {
switch a {
case .Some(let x): return f(x)
case .None: return .None
}
}
Then we can compose multiple options together using apply, which we'll call <*>
because we're cool (and we know some Haskell)
// <*> is the commonly-accepted symbol for apply
infix operator <*> { associativity left }
func <*><A, B>(f: (A -> B)?, a: A?) -> B? {
switch f {
case .Some(let value): return value <^> a
case .None: return .None
}
}
Now we can rewrite our example
doStuff <^> optA <*> optB
This will work, provided that doStuff
is in curried form (see below), i.e.
func doStuff(a: A)(b: B) -> C { ... }
The result of the whole thing is an optional value, either nil
or the result of doStuff
Here's a complete example that you can try in the playground
func sum(a: Int)(b: Int) -> Int { return a + b }
let optA: Int? = 1
let optB: Int? = nil
let optC: Int? = 2
sum <^> optA <*> optB // nil
sum <^> optA <*> optC // Some 3
As a final note, it's really straightforward to convert a function to its curried form. For instance if you have a function taking two parameters:
func curry<A, B, C>(f: (A, B) -> C) -> A -> B -> C {
return { a in { b in f(a,b) } }
}
Now you can curry any two-parameter function, like +
for example
curry(+) <^> optA <*> optC // Some 3