157

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?

Wes Campaigne
  • 4,060
  • 3
  • 22
  • 17
  • 3
    Possibly related: [Does Swift have a null coalescing operator and if not, what is an example of a custom operator?](http://stackoverflow.com/questions/24082959/does-swift-have-a-null-coalescing-operator-and-if-not-what-is-an-example-of-a-c) – Martin R Jun 07 '14 at 17:50

5 Answers5

316

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.

drewag
  • 93,393
  • 28
  • 139
  • 128
  • my complier shows me that the type of `unwrappedValue` is still the optional type for this case in Swift 1.2: `var unwrappedValue = optionalValue ? optionalValue! : defaultValue` (xcode 6 beta 4). Has this changed? – SimplGy Aug 14 '15 at 11:55
  • 2
    I'm wrong on my version. I'm on 6.4. Be aware: `??` default type inference behavior is that it returns an optional, which is not what you want typically. You can declare the variable as non-optional and this works nicely. – SimplGy Aug 14 '15 at 12:25
31

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"
MirekE
  • 11,515
  • 5
  • 35
  • 28
7

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

UnRewa
  • 2,462
  • 2
  • 29
  • 31
3

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
Wes Campaigne
  • 4,060
  • 3
  • 22
  • 17
  • You do not need to specify `T` for the method. That actually overrides the existing `T` from Optional. You can just do: `func getOrElse(defaultValue: T) -> T` then T refers to the real value type of the optional and you don't have to type check it – drewag Jun 07 '14 at 18:03
  • Thanks! I inferred exactly that from the second half of your response. Is there some way to inspect the definition of Optional to know that the generic type is defined as `T` in that? (beyond simply assuming based on convention) – Wes Campaigne Jun 09 '14 at 02:08
  • If you command-click on `Optional` inside Xcode, you will see that it is defined as `enum Optional` – drewag Jun 09 '14 at 02:10
  • Oh, excellent. I should have guessed. The definitions in there will be useful; there's a lot of things that aren't in the documentation yet. Thanks again. – Wes Campaigne Jun 09 '14 at 02:22
0

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

string1 = string2.isEmpty ? "Default Value":string2
Plasma
  • 2,622
  • 2
  • 20
  • 35