Optionally Do !?

Swift: Optionally Do — Re-thinking If Let

Sometimes I wish there was a shorthand version.

Mark Robinson
jtribe
Published in
7 min readSep 8, 2016

--

I know, I know, it’s short enough. That’s what people keep telling me, but hear me out for a second.

??

We have the ?? operator in Swift, and it’s great because it’s a shorthand way of supplying a default value to an optional if it happens to be .None. For example:

What are the advantages? Well, it’s succinct (which isn’t always better but in this case I think we can call it a plus point), it’s elegant, it reduces noise, and it’s also clear to the programmer what is happening given they’re aware of the operator.

I think it’s safe to say that using ?? is strictly better than the alternative, so with that thought in mind, I began to wonder “what can we do with if let…?”

jtribe — Love Your Apps!

What’s Wrong With If Let?

Listen, I love if let and guard let as much as the next person. I think they’re great and all, but sometimes I just wish I didn’t need to write the full if let statement to unwrap and make sure the property I’m using is a non-optional.

In fact, sometimes before using a function there can be a number of optionals that I need to if let — which may bring flashbacks of the pyramid of doom to some of us — before I know it’s safe to use them. Why can’t we have a short-hand notation?

I’m not promising what i’ve got here is thorough in any way, shape or form and I can break it quite easily, so lets call this a thought experiment. Maybe you guys can think of some improvements or why it’s a good or bad idea, so please let me know your thoughts by commenting below.

Operator Abuse

Now before I go introducing you to this operator, I just have to prefix this by saying…

I really dislike the abuse of operators in programming where it compromises the readability of the code.

For example, take the JSON parsing library Argo from the guys at thoughtbot:

extension User: Decodable {
static func decode(j: JSON) -> Decoded<User> {
return curry(User.init)
<^> j <| "id"
<*> j <| "name"
<*> j <|? "email" // Use ? for parsing optional values
<*> j <| "role" // Custom types that also conform to Decodable just work
<*> j <| ["company", "name"] // Parse nested objects
<*> j <|| "friends" // parse arrays of objects
}
}

U WOT M8!? 😦

Good luck understanding anything about how that library works or what the code is doing from their “Usage tl;dr” at the bottom of the Github README. I’m sure it’s all sunshine and rainbows when you figure out what all the hieroglyphs mean but I’m not ancient Egyptian my friends, I’m not doing it.

On the other hand, take a look at the awesome SwiftyJSON:

//Getting a double from a JSON Array
let name = json[0].double
//Getting a string from a JSON Dictionary
let name = json["name"].stringValue
//Getting a string using a path to the element
let path = [1,"list",2,"name"]
let name = json[path].string
//Just the same
let name = json[1]["list"][2]["name"].string
//Alternatively
let name = json[1,"list",2,"name"].string

You can almost instantly tell exactly what it is doing with very little investment.

Alright, I got that out of my system. We’ve well and truly established that I don’t like operator abuse which compromises readability. So why on earth am I making an operator that obfuscates the if let?

Well… I don’t think it does. Much. Allow me to explain.

The Optionally Do— ?!

I came up with the idea of the Optionally Do operator — ?!

(left hand side) ?! (right hand side)
lhs ?! rhs

This operator should be read as lhs optionally do what is on the rhs, given that the lhs is a non-optional

The ? stipulates that the left-hand side (lhs) of the expression is some kind of Optional value. The succeeding ! means that the right-hand side will only execute should the lhs be successfully unwrapped.

Ok, so you might not like the operator or the name, but lets put that aside for a second. We can change that easily. Lets see what i’d love to be able to do.

I’ll highlight the examples below with comments at the top of the code block where the code will compile, and i’ll let you know when I get to theoretical land (given my current definition of the operator above).

Here’s my really basic definition:

Yeah I know, I said it was basic. Sometimes we want to call a function, even if the value we’re checking isn’t going to be used. Wouldn’t it be great that instead of having to write something like this:

We could just write this instead?

mark ?! printHello // prints HELLO

i.e. print HELLO if mark is non optional

Just like ??, it’s succinct, it’s elegant, it reduces noise and it’s also clear to the programmer what is happening given they’re (now) aware of the operator. What if we do need to use the value in the function?

// compilesfunc sayHi(to someone: String) {
print(“Hello \(someone)”)
}
mark ?! sayHi // prints Hello mark

I think the above is cool in the sense that I don’t even need to say that I want to use mark as an argument explicitly by calling sayHi(mark) and that the compiler can infer it, but it’s not immediately obvious to the programmer so I don’t think it can be held in the same regard as the advantages of the previous example or the ?? operator. However, what we can write instead is

// compilesmark ?! { sayHi(to: $0) }

Which is better, because now I know what’s happening as the programmer. It’s a lot more readable but i’d rather we didn’t have to have the { } at all and could just write

// theoreticalmark ?! sayHi(to: $0)// ORmark ?! sayHi(to: mark)

…which achieves the same purpose and is a lot cleaner than before.

Now that’s great and all, but I think the real value would be if we have a number of optionals, of different types, that we need to unwrap before using a particular function. I’ve made this rubbish definition that’ll take a tuple of two different (or the same) typed optionals, just for demonstrative purposes. The entire tuple of optionals need to be evaluated and successfully unwrapped before the right-hand side of the expression is executed.

Now I don’t know about you, but I think that looks quite a bit cleaner. Although I appreciate we might not see the advantages fully with only two optional values and a generic print function, but what if we had something like:

// theoretical// BEFORE
if let mark = mark, _ = thomas, something = something, yo = yo {
doSomething(mark, something, yo)
}
// AFTER
(mark, thomas, something, yo) ?! doSomething($0, $2, $3)
// OR(mark, thomas, something, yo) ?! doSomething(mark, something, yo)

You can see how it can be a lot more elegant than a traditional if let by now while still having perfect readability. The before example actually gets even worse in Swift 3 (or better, depending on your perspective) because you explicitly have to prefix every x = x with let or var. It’s just so needlessly long.

Though there is a scenario (many actually, this is a thought experiment, remember?) — where we’re doing multiple unwrapping and there is a dependency between the properties — that I can’t really think of how this new operator would tidy up the code:

// theoretical// BEFORE
if let urlString = json[“webAddress”].string,
url = NSURL(string: urlString),
target = Target(url: url),
ultimateCoolModel = UltimateCoolModel(some: urlString) {
use(ultimateCoolModel)
useOther(target)
}
// AFTER ?
json[“webAddress”].string ?! { urlString in
NSURL(string: urlString)
?! Target(url: $0)
?! UltimateCoolModel($0)
?! {
use($0)
userOther(urlString)
}
}

And then it just looks way worse. It starts to look too close to what I was complaining about with Argo Vs SwiftyJSON and it hinders readability in a big way.

Closing Comments

Anyway, as I said before, this was just me messing around in XCode Playgrounds as a thought exercise to try to get some discussion going on how we can make if let even better.

If you have any suggestions for how we can improve the idea of the Optionally Do ?! operator then i’d be glad to hear it. If you don’t like the idea and think it’s rubbish, then that’s cool too, i’d like to hear that also so please leave comments below.

If you’ve gotten this far and enjoyed the article, please take a second to click the recommend and share buttons below. It would be much appreciated. Cheers — Mark

About Us

At jtribe, we proudly craft software solutions for iOS, Android and Web and are passionate about our work. We’ve been working with the iOS and Android platforms since day one, and are one of the most experienced mobile development teams in Australia. We measure success on the impact we have, and with over six-million end users we know our work is meaningful, and this continues to be our driving force.

--

--

Mark Robinson
jtribe
Writer for

Mobile Dev @rome2rio. Football & F1 enthusiast. Burger aficionado. Tech WZRD. Dog Lover. All around top lad.