Ashley Mills
Ashley Mills

Reputation: 53111

Swift: adding optionals Ints

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?

Upvotes: 8

Views: 4176

Answers (7)

user652038
user652038

Reputation:

Someday, we'll have variadic generics. Until then, you need a pair of overloads for all arities.

var z = Optional(x, y).map(+)
public extension Optional {
  /// Exchange two optionals for a single optional tuple.
  /// - Returns: `nil` if either tuple element is `nil`.
  init<Wrapped0, Wrapped1>(_ optional0: Wrapped0?, _ optional1: Wrapped1?)
  where Wrapped == (Wrapped0, Wrapped1) {
    self = .init((optional0, optional1))
  }

  /// Exchange two optionals for a single optional tuple.
  /// - Returns: `nil` if either tuple element is `nil`.
  init<Wrapped0, Wrapped1>(_ optionals: (Wrapped0?, Wrapped1?))
  where Wrapped == (Wrapped0, Wrapped1) {
    switch optionals {
    case let (wrapped0?, wrapped1?):
      self = (wrapped0, wrapped1)
    default:
      self = nil
    }
  }
}

Upvotes: 0

MaatheusGois
MaatheusGois

Reputation: 194

Swift 5.5 Sum any optional values

infix operator +?: AdditionPrecedence

public func +? <T: AdditiveArithmetic>(lhs: T?, rhs: T?) -> T {
    if let lhs = lhs, let rhs = rhs {
        return lhs + rhs
    } else if let lhs = lhs {
        return lhs
    } else if let rhs = rhs {
        return rhs
    } else {
        return .zero
    }
}

Upvotes: -1

Charles Dassonville
Charles Dassonville

Reputation: 207

z = (x ?? 0) + (y ?? 0)

* Worked on Xcode 9 *

Upvotes: -2

Fab1n
Fab1n

Reputation: 2284

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!).

Upvotes: 3

Chris Conover
Chris Conover

Reputation: 9039

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

Upvotes: 4

Grimxn
Grimxn

Reputation: 22487

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 "+?".

Upvotes: 2

Jack
Jack

Reputation: 16855

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.

Upvotes: 2

Related Questions