0

As far as I know the recommended way to use optionals (Int in this example) is the following:

var one:Int?

if var maybe = one {
  println(maybe)
}

Is it possible to use a shorter way to do something like the following?

var one:Int?
var two:Int?
var three:Int?

var result1 = one + two + three // error because not using !
var result2 = one! + two! + three! // error because they all are nil

Update

To be more clear about what I'm trying to do: I have the following optionals

var one:Int?
var two:Int?
var three:Int?

I don't know if either one or two or three are nil or not. If they are nil, I wan't them to be ignored in the addition. If they have a value, I wan't them to be added.

If I have to use the recommended way I know, it would look something like this: (unnested)

var result = 0

if var maybe = one {
  result += maybe
}
if var maybe = two {
  result += maybe
}
if var maybe = three {
  result += maybe
}

Is there a shorter way to do this?

Linus
  • 4,643
  • 8
  • 49
  • 74

2 Answers2

3

That's exactly the point of optionals — they may be nil or non-nil, but unwrapping them when they're nil is an error. There are two types of optionals:

T? or Optional<T>

var maybeOne: Int?
// ...

// Check if you're not sure
if let one = maybeOne {
    // maybeOne was not nil, now it's unwrapped
    println(5 + one)
}

// Explicitly unwrap if you know it's not nil
println(5 + one!)

T! or ImplicitlyUnwrappedOptional<T>

var hopefullyOne: Int!
// ...

// Check if you're not sure
if hopefullyOne {
    // hopefullyOne was not nil
    println(5 + hopefullyOne)
}

// Just use it if you know it's not nil (implicitly unwrapped)
println(5 + hopefullyOne)

If you need to check multiple optionals at once here there are a few things you might try:

if maybeOne && maybeTwo {
    println(maybeOne! + maybeTwo!)
}

if hopefullyOne && hopefullyTwo {
    println(hopefullyOne + hopefullyTwo)
}

let opts = [maybeOne, maybeTwo]
var total = 0
for opt in opts {
    if opt { total += opt! }
}

(It seems you can't use the let optional binding syntax with more than one optional at once, at least for now...)

Or for extra fun, something more generic and Swifty:

// Remove the nils from a sequence of Optionals
func sift<T, S: Sequence where S.GeneratorType.Element == Optional<T>>(xs: S) -> GeneratorOf<T> {
    var gen = xs.generate()
    return GeneratorOf<T> {
        var next: T??
        do {
            next = gen.next()
            if !next { return nil } // Stop at the end of the original sequence
        } while !(next!) // Skip to the next non-nil value
        return next!
    }
}

let opts: [Int?] = [1, 3, nil, 4, 7]
reduce(sift(opts), 0) { $0 + $1 } // 1+3+4+7 = 15
jtbandes
  • 115,675
  • 35
  • 233
  • 266
  • So what way to use? `ImplicitlyUnwrappedOptional` seems more simple – Maxim Shoustin Jul 09 '14 at 07:25
  • So there is only the "long" way I've mentioned in my question? – Linus Jul 09 '14 at 07:27
  • I would suggest reading [this answer](http://stackoverflow.com/a/24026196/23649) or [the Swift guide](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_427), especially "Note: Implicitly unwrapped optionals should not be used when there is a possibility of a variable becoming nil at a later point. Always use a normal optional type if you need to check for a nil value during the lifetime of a variable." – jtbandes Jul 09 '14 at 07:28
  • @LinusAn I don't understand what you mean by the "long" way. Implicitly unwrapped optionals allow you to use the variable as if it weren't optional, so it's very similar to just using a non-optional variable. – jtbandes Jul 09 '14 at 07:28
  • @jtbandes by "long" way I mean that I first have to check if the variable is nil in an if statement, then, if it's not, use it in the if body. When I do this with 5 numbers, it gets very long. – Linus Jul 09 '14 at 07:32
  • Of course that's only necessary if you don't know whether the variable is nil. If you already know, then you can just use it (see the last line of each of my examples). – jtbandes Jul 09 '14 at 07:33
  • @jtbandes don't get me wrong, you've provided a nice example but it's not answering my question. I gave you an upvote because your answer is generally useful. – Linus Jul 09 '14 at 07:45
  • @LinusAn Now that you've provided more examples, I think I understand your question better. I'll edit my answer appropriately! – jtbandes Jul 09 '14 at 07:48
3

Quick note - if let is preferred for optional binding - let should always be used where possible.

Perhaps Optionals aren't a good choice for this situation. Why not make them standard Ints with a default value of 0? Then any manipulation becomes trivial and you can worry about handling None values at the point of assignment, rather than when you're working on the values?

However, if you really want to do this then a tidier option is to put the Optionals into an Array and use reduce on it:

    let sum = [one,two,three,four,five].reduce(0) {
        if ($1) {
            return $0 + $1!
        }
        return $0
    }
jrturton
  • 118,105
  • 32
  • 252
  • 268