Nil-coalescing Operator in Swift

Update: As of Xcode 6 Beta 5 this article is obsolete. Swift now includes a nil coalescing operator (??). I am leaving this article on my blog for people who are curious about why such an operator exists or when to use it.

Working with optionals in Swift can lead to a lot of uninteresting code that unwraps a value and, if it is nil, uses a suitable default value. The problem is compounded by the fact that Swift requires if/else bodies to be enclosed with { braces }. This can cause what should be a simple, small piece of code to become tedious and verbose.

Consider a simple scenario where the user can type a number into a UITextField, which is then parsed from a String to an Int and stored in a data object. String.toInt() returns an Optional<Int> because not all strings can be parsed to an integer value. Regardless of this minor complication, there is no reason why performing such a task should require more than one line of code.

As seen in the last example above, I created a custom operator function, dubbed the nil-coalescing operator. That operator function evaluates to an optional’s value unless it is nil, in which case it evaluates to a fallback/default value. This is based on the null-coalescing operator in C#, which is formed by two adjacent question marks (??). Since Swift does not allow custom operator functions to include a question mark (correction: it does as of Xcode 6 Beta 5), I instead opted for two adjacent exclamation marks (!!). I think of it as “If the optional cannot be unwrapped (because it’s nil), then use this value instead.”

It’s important to note that the expression on the right-hand side of the operator does not execute unless the left-hand expression evaluates to nil. I accomplished that intuitive and expected behavior by making use of “auto-closures”; a relatively obscure Swift feature that allows you to create closures without using { braces }.

Here is a GitHub gist that shows the nil-coalescing operator definition and a few use cases.


//
// UPDATE: This gist was rendered obsolete as of
// Xcode 6 Beta 5, which introduced the nil
// coalescing operator in Swift proper (??).
//
/* Nil-coalescing operator */
infix operator !! {}
func !! <T> (
value: T?,
defaultValue: @auto_closure () -> T)
-> T
{
return value ? value! : defaultValue()
}
let text = "13"
let number = text.toInt() !! 0
println(number)
// prints: 13
println("word".toInt() !! 99 + 1)
// prints: 100
// Prints a message to show when it executes.
func getDefaultNumber() -> Int
{
print("Getting the default number…")
return -1
}
println("42".toInt() !! getDefaultNumber())
// prints: 42
println("Josh".toInt() !! getDefaultNumber())
// prints: Getting the default number…-1

view raw

main.swift

hosted with ❤ by GitHub

Notice that the second to last example does not cause the getDefaultNumber() function to execute, but the last example does because it’s optional value is nil.


I’d like to thank my friend Jordan Nolan for bringing this point up and nudging me to work out a solution.
This entry was posted in Swift and tagged , . Bookmark the permalink.

21 Responses to Nil-coalescing Operator in Swift

  1. Mark Patterson says:

    That looks really useful. I wonder if there is a possible ambiguity with the ! also being the not operator? But I like that idea.

    • Josh Smith says:

      Thanks Mark. I’m certainly not a language designer, so there might be a better choice of symbols to use for the custom operator function. So far, after testing it out in a few situations I haven’t hit any snags. I chose !! because I think of it as “NOT unwrappable”, which ties together the logical not operator (!) and the unwrap operator (!). After poking around the Web a bit since posting this article, I found that others have already implemented this with different operator symbols, such as on StackOverflow http://bit.ly/1pfZfiC Maybe you’ll like their implementations better? Either way, Swift is loads of fun!

  2. That is absolutely beautiful, and the first useful application of auto-closures I have seen outside of the ‘assert’ use-case.

  3. Pingback: Dew Drop – July 25, 2014 (#1822) | Morning Dew

  4. Mike Brown says:

    I am loving this series Josh does Apple have an MVP program lol

  5. Andrew says:

    I think it is way more understandable to use “or” instead of an operator, especially because it is the same number of characters. I actually wrote an extension to Optional for this: https://github.com/drewag/SwiftPlusPlus/blob/master/SwiftPlusPlus/Optional%2BSwiftPlusPlus.swift

    • Andrew says:

      This allows code like this:

      var optionalString: String?
      var unwrappedString = optionalString.or(“Default Value”)
      println(unwrappedString) // “Default Value”

      optionalString = “Other Value”
      println(optionalString.or(“Default Value”)) // “Other Value”

      However, I think your idea of using @auto_closure would improve my implementation

      • Josh Smith says:

        That’s interesting. I prefer not to add a method on Optional that can be called on the object when it has no value (nil). That seems counterintuitive to me. Wouldn’t it allow code like this?
        let isNil = optionalBool.or(true)
        In my mind, that “should” cause an error since you’re calling a method on a nil object reference, which isn’t ignored in Swift like in Obj-C.
        In any case, thanks for sharing it here.

      • Andrew says:

        Interesting that you find that counterintuitive as it feels natural to me, I guess it is just a matter of personal preference :). Maybe that is because I am so in the mindset that Optional is just an enum. You can already call a method on Optional to check if it is nil (using the LogicValue protocol). It seems natural to me to have a similar check for nil that provides a default value.

      • Josh Smith says:

        To me, the fact that optionals are actually an enum is an implementation detail, which exists to support the ? and ! syntax. When reading/writing code I prefer to think of optional values as a “thing” in their own right, not as the underlying infrastructure that enables it. Like you said, it’s personal preference.

    • Mark Patterson says:

      To make that more usable, wouldn’t it be better to pass a closure, so that it doesn’t have to be evaluated if not needed? I tried this out:

      extension Optional { /// Unwrap the value returning ‘defaultValue’ if the value is nil
      func or(defaultValue: @auto_closure () -> T) -> T {
      switch(self) {
      case .None:
      return defaultValue()
      case .Some(let value):
      return value
      }
      }
      }

  6. Pingback: Michael Tsai - Blog - Nil-coalescing Operator in Swift

  7. Pingback: Swift around the web | Swift for Flash Developers Blog

  8. nschum says:

    As an aside: Objective-C also has this, because the second operand in ?: is optional. So it’s: “wheels ?: 4”

    (Technically that’s a GCC/LLVM compiler extension to C, but that makes it official-ish for Objective-C.)

    I hope Apple just adds this. Everybody please file a radar while Swift is still in flux. 🙂

    • Andrew says:

      FYI, Chris Lattner (a member if the swift team) has explicitly said on the developer forums that they do not prioritize features based on duplicate radars. Save yourself and them the time and don’t bother filing known duplicate requests

    • Josh Smith says:

      Good point about ?: in obj-c. I use that a lot, though I always just thought of it as a shorthand for the ternary operator. The ?? op in C# was introduced to streamline Nullable, the .NET equivalent of optionals. I suppose they’re the same thing!

  9. Mark Patterson says:

    i’m not sure this is great as a language feature from an overall point of view. Having default values is the very sort of thing optionals were added to avoid.

    • Josh Smith says:

      Optionals prevent the need for sentinel values, such as NSNotFound (-1). That is different from a default value, which is a problem domain concern.

      • Mark Patterson says:

        Fair enough, but rarer I would think. It is nice to see how easy it is the add that sort of thing to the syntax if you judge it best. But if it were part of the language, people might start reverting to old sentinel habits.

Comments are closed.