Swift Sugar For Optional Ternary Operators

It is a common situation that an optional parameter is being passed into a function and that some other parameter needs to be set based on whether or not the optional parameter is nil or contains a value.

A typical way of handling this in Swift might be to use the if-let syntax as so:

func aFunction(optionalParameter: String?) {

    var dependentParameter = ""

    if let _ = optionalParameter {
        dependentParameter = valueIfNotNil
    } else {
        dependentParameter = valueIfNil
    }
    //do something with dependentParameter
}

This is fine and works correctly. One improvement that may not be obvious is that the dependentParameter can be declared as an unassigned let as long as the compiler can guarantee that it is assigned prior to being used:

func aFunction(optionalParameter: String?) {

    let dependentParameter: String?

    if let _ = optionalParameter {
        dependentParameter = valueIfNotNil
    } else {
        dependentParameter = valueIfNil
    }
    //do something with dependentParameter
}

So, those constructions work, but for merely assigning a value it’s annoying to use 5 lines of code. Also, I prefer to use if-else blocks for doing some task, rather than for setting values.

I could use a ternary statement, but we can’t use let _ = optionalParameter syntax there for the switching logic. In Objective-C, we can take advantage of the fact that it treats nil the same as false, so we’d have the nice compact:

NSString *dependentParameter = optionalParameter ? valueIfNotNil : valueIfNil

In Swift, since if let _ = optionalParameter is just syntactic sugar for optionalParameter != nil we could do the following:

let dependentParameter = optionalParameter != nil ? valueIfNotNil : valueIfNil

It’s fine, but… the != nil does make things a little visually cluttered and therefore harder to follow. Especially if you were to add parentheses to clarify precedence:

let dependentParameter = (optionalParameter != nil) ? valueIfNotNil : valueIfNil

It would be nice to have something a little cleaner like the ObjC version, while retaining the Swift safety. Something like this:

let dependentParameter = optionalParameter ??? valueIfNotNil ||| valueIfNil

Soooo… it’s operator overloading time!

infix operator ??? : TernaryPrecedence
infix operator ||| : AdditionPrecedence

func ???(input: String?, valuesBlock: ((String?) -> String)) -> String {
    return valuesBlock(input)
}

func |||(ifNotNil: String, ifNil: String) -> ((String?) -> String) {
    return { (input: String?) -> String in
        if let _ = input {
            return ifNotNil
        } else {
            return ifNil
        }
    }
}

Tada!

var optionalParameter: String? = nil

let yeahItsNil = optionalParameter ??? valueIfNotNil ||| valueIfNil
print(yeahItsNil) // result: valueIfNotNil
optionalParameter = "string"

let notNil = optionalParameter ??? valueIfNotNil ||| valueIfNil
print(notNil) // result: valueIfNotNil

I should probably do a little more reading, because I bet there is a Ruby equivalent. I will update if there is.

Gist here: https://gist.github.com/chrisbrandow/7eb91366075f33fb8ec01bacb11454bb.js

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s