150
votes

The idiom for dealing with optionals in Swift seems excessively verbose, if all you want to do is provide a default value in the case where it's nil:

if let value = optionalValue {
    // do something with 'value'
} else {
    // do the same thing with your default value
}

which involves needlessly duplicating code, or

var unwrappedValue
if let value = optionalValue {
    unwrappedValue = value
} else {
    unwrappedValue = defaultValue
}

which requires unwrappedValue not be a constant.

Scala's Option monad (which is basically the same idea as Swift's Optional) has the method getOrElse for this purpose:

val myValue = optionalValue.getOrElse(defaultValue)

Am I missing something? Does Swift have a compact way of doing that already? Or, failing that, is it possible to define getOrElse in an extension for Optional?

5

5 Answers

305
votes

Update

Apple has now added a coalescing operator:

var unwrappedValue = optionalValue ?? defaultValue

The ternary operator is your friend in this case

var unwrappedValue = optionalValue ? optionalValue! : defaultValue

You could also provide your own extension for the Optional enum:

extension Optional {
    func or(defaultValue: T) -> T {
        switch(self) {
            case .None:
                return defaultValue
            case .Some(let value):
                return value
        }
    }
}

Then you can just do:

optionalValue.or(defaultValue)

However, I recommend sticking to the ternary operator as other developers will understand that much more quickly without having to investigate the or method

Note: I started a module to add common helpers like this or on Optional to swift.

30
votes

As of Aug 2014 Swift has coalescing operator (??) that allows that. For example, for an optional String myOptional you could write:

result = myOptional ?? "n/a"
5
votes

if you wrote:

let result = optionalValue ?? 50

and optionalValue != nil then result will be optional too and you will need unwrap it in future

But you can write operator

infix operator ??? { associativity left precedence 140 }

func ???<T>(optLeft:T?, right:T!) -> T!
{
    if let left = optLeft
    {
        return left
    }
    else { return right}
}

Now you can:

 let result = optionalValue ??? 50

And when optionalValue != nil then result will be unwraped

3
votes

The following seems to work

extension Optional {
    func getOrElse<T>(defaultValue: T) -> T {
        if let value = self? {
            return value as T
        } else {
            return defaultValue
        }
    }
}

however the need to cast value as T is an ugly hack. Ideally, there should be a way to assert that T is the same as the type contained in the Optional. As it stands, type inferencing sets T based on the parameter given to getOrElse, and then fails at runtime if this does not match the Optional and the Optional is non-nil:

let x: Int?

let y = x.getOrElse(1.414) // y inferred as Double, assigned 1.414

let a: Int? = 5

let b: Double = a.getOrElse(3.14) // Runtime failure casting 5 to Double
0
votes

If you are trying to do this with a String you can do this ..

string1 = string2.isEmpty ? "Default Value":string2