Question or problem in the Swift programming language:
I declare the following:
var x:Int? var y:Int?
and I’d like a third variable z that contains the sum of x and y. Presumably, as x & y are optionals, z must also be an optional:
var z:Int? = x + y
but this gives a complier error “value of optional type ‘Int?’ not unwrapped; did you mean to use ‘!’ or ‘?'”
If I unwrap x & y:
var z:Int? = x! + y!
I get a run-time error as x & y are nil, so can’t be unwrapped.
I can achieve the desired result as follows:
var z:Int? if let x1 = x { if let y1 = y { z = x1+y1 } }
but this seems a bit verbose for adding together 2 integers! Is there a better way of achieving this?
How to solve the problem:
Solution 1:
Here is my take, I think it’s cleaner:
let none:Int? = nil let some:Int? = 2 func + (left: Int?, right:Int?) -> Int? { return left != nil ? right != nil ? left! + right! : left : right } println(none + none) println(none + some) println(some + none) println(some + some) println(2 + 2)
With results of:
nil Optional(2) Optional(2) Optional(4) 4
Solution 2:
The best I can think of is:
if x && y { z = x! + y!; }
Since they are all Optionals… there’s really no way to avoid:
- checking that they aren’t
nil
- Unwrapping them before you add them.
Solution 3:
Best solution IMO:
z = x.map { x in y.map { $0 + x } }
Did you know the map operator on Optional<T>
? It is very nice.
Documentation says:
If self == nil, returns nil. Otherwise, returns f(self!).
Solution 4:
It depends exactly what you’re trying to achieve, but you could do it with an optional tuple:
var xy: (Int, Int)? var z: Int if let (x1, y1) = xy { z = x1 + y1 // Not executed } xy = (3, 4) if let (x1, y1) = xy { z = x1 + y1 // 7 }
Update
As @Jack Wu points out, this changes the semantics. If you were willing to be a bit more verbose, you could however do it as follows:
func optIntAdd(x: Int?, y: Int?) -> Int? { if let x1 = x { if let y1 = y { return x1 + y1 } } return nil } operator infix +! { } @infix func +! (x: Int?, y: Int?) -> Int?{ return optIntAdd(x, y) } var x: Int? var y: Int? var z: Int? z = x +! y // nil x = 1 z = x +! y // nil y = 2 z = x +! y // 3
Not sure “+!” is a useful choice of name for the operator, but it would’t let me choose “+?”.
Solution 5:
z = (x ?? 0) + (y ?? 0)
* Worked on Xcode 9 *
Solution 6:
Use optional chaining:
z = x? + y?