1

I'm looking for a solid, repeatable pattern for filling in an optional value. The behavior I want is "if it's nil, use this default".

I have three ways to approach it so far.

// Three approaches for using a default value when the optional is nil
// Device.location is an optional `CLLocation?`
// cfg.defaultLocation is `CLLocation`


// 1: bitwise (nice and short, requires a holding variable)
let location1: CLLocation! = Device.location ?? cfg.defaultLocation
positionMap(location1)

// 2: if let (sooooo many lines!)
if let location2 = Device.location {
  positionMap(location2)
} else {
  positionMap(cfg.defaultLocation)
}

// 3: re-wrap (holding var :( )
let location3: CLLocation! = Device.location
positionMap(location3 ?? cfg.defaultLocation)

You guys have a better way to do this? Comes up a lot for me.

SimplGy
  • 20,079
  • 15
  • 107
  • 144
  • The first option is actually a shorthand form of the fourth. I like that one the most. It shouldn't require the use of the temporary `location1` variable, though. You can feed the RHS expression directly into the function call. – hennes Aug 14 '15 at 11:59

1 Answers1

3

My approach to this is by using computed properties. The biggest disadvantage of using these is that you always compute property value and thats of course take some processing resources. But on the other hand the biggest advantage is that if sometime during application life the optional value change then you don't have to change your non optional variable (that hold default value) manually.

let location : CLLocation {
    return Device.location ?? cfg.defaultLocation
}
Zell B.
  • 10,266
  • 3
  • 40
  • 49
  • This is pretty sweet. Isn't in dependent on the `??` operator returning an unwrapped object, which only changed in xcode 6 beta 5? How are you all on a higher version of xcode than me? :) – SimplGy Aug 14 '15 at 12:07
  • @SimplGy Well the whole idea behind this is computed property, so inside the block you can use each of methods you mentioned in your question. Btw I would prefer the second one – Zell B. Aug 14 '15 at 12:11
  • I'm getting confusing results: `let loc1 = Device.location ?? cfg.defaultLocation // type optional CLLocation` but `let loc2: CLLocation = Device.location ?? cfg.defaultLocation // type: non-optional CLLocation`. In xcode 6 beta 4 at least, the default return value of `??` is wrapped in an optional, but you can change it by declaring the type. Works great in a getter. – SimplGy Aug 14 '15 at 12:14
  • @SimplGy: Xcode 6 beta 5 is about a year old (which is an era in Swift dimensions). The current *released* version is Xcode 6.4 and available in the App Store. – Martin R Aug 14 '15 at 12:17
  • Oh, oops, I'm reading my version number wrong. 6.4. Not 6 beta 4. This means the `??` operator type infers the return as an optional by default... so be aware. [Some answers](http://stackoverflow.com/a/24100008/111243) on this are not correct. If you stuff it into a non-optional var it'll work correctly. – SimplGy Aug 14 '15 at 12:23
  • @SimplGy: That is not quite correct. The result type of `??` is that of its rhs, which can be an optional or not. Strictly speaking there are two separate operators `public func ??(optional: T?, @autoclosure defaultValue: () -> T?) -> T?` and `public func ??(optional: T?, @autoclosure defaultValue: () -> T) -> T`. – Martin R Aug 14 '15 at 12:34
  • @SimplGy: Just try `let a : Int? = 1 ; let b : Int = 2 ; let c = a ?? b`. The type of `c` is `Int`, not `Int?`. – Martin R Aug 14 '15 at 12:41
  • Ah, this is my mistake. I had a rhs of `Type?` and a lhs of `Type!`. Naturally, this returns an optional. My bad! – SimplGy Aug 14 '15 at 12:46