Swift: adding optionals Ints

i0S Swift Issue

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:

  1. checking that they aren’t nil
  2. 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?

Hope this helps!