In Swift, How to Avoid Both Optionals and Nil Object References

In Swift, how do I avoid both optionals and nil object references?

You’re right, optionals can be a pain, which is why you shouldn't overuse them. But they're more than just something you have to deal with when using frameworks. They're a solution to an incredibly common problem: how to handle a call that returns a result that might be OK, or might not.

For example, take the Array.first member. This is a handy utility that gives you the first element of an array. Why is it useful to be able to call a.first, when you could just call a[0]? Because at runtime the array might be empty, in which case a[0] will explode. Of course you can check a.count beforehand – but then again

a. you might forget,

and

b. that results in quite ugly code.

Array.first deals with this by returning an optional. So you are forced to unwrap the optional before you can use the value that is the first element of the array.

Now, to your issue about the unwrapped value only existing inside the block with if let. Imagine the parallel code, checking the array count. It would be the same, right?

if a.count > 0 {
// use a[0]
}
// outside the block, no guarantee
// a[0] is valid

if let firstElement = a.first {
// use firstElement
}
// outside the block, you _can't_
// use firstElement

Sure, you could do something like perform an early return from the function if the count is zero. This works but is a bit error-prone – what if you forgot to do it, or put it in a conditional statement that didn't happen to run? Essentially you can do the same with array.first: check the count early in the function, and then later on do array.first!. But that ! is like a signal to you – beware, you are doing something dangerous and you will be sorry if your code isn't completely correct.

Optionals also help make the alternatives slightly prettier. Suppose you wanted to default the value if the array was empty. Instead of this:

array.count > 0 ? a[0] : somedefault

you can write this:

array.first ?? somedefault

This is nicer in several ways. It puts the important thing up front: the value you want is how the expression starts, followed by the default. Unlike the ternary expression, which hits you first with the checking expression, followed by the value you actually want, then finally the default. It's also more foolproof – much easier to avoid making a typo, and impossible for that typo to result in a runtime explosion.

Take another example: the find function. This checks if a value is in a collection and returns the index of its position. But the value may not be present in the collection. Other languages might handle this by returning the end index (which doesn't point to a value but rather one past the last value). This is what's termed a "sentinel" value – a value that looks like a regular result, but actually has special meaning. Like the previous example, you’d have to check the result was not equal to the end index before using it. But you have to know to do this. You have to look up the docs for find and confirm that's how it works.

With find returning an optional it's just natural, when you understand the optional idiom, to realize that the reason it does is because the result might not be valid for the obvious reason. And all the same things about safety mentioned above also apply – you can’t accidentally forget, and use the result as an index, because you have to unwrap it first.

That said, you can over-use optionals as they are a burden to have to check. This is why array subscripts don't return optionals – it would create so much hassle to have to constantly check and unwrap them, especially when you know for a fact that the index you're using is valid (for example, you're in a for loop over a valid index range of the array) that people would be using ! constantly, and thus clutter their code without benefit. But then the helper methods like first and last are added to cover common cases where people do want to quickly do an operation without having to check the array size first, but want to do it safely.

(Swift Dictionaries, on the other hand, are expected to be regularly accessed via invalid subscripts, which is why their [key] method does return an optional)

Even better is if the possibility of failure can be avoided altogether. For example, when filter matches no elements, it doesn’t return a nil optional. It returns an empty array. “Well obviously it would”, you might say. But you’d be surprised how often you see someone making a return value like an array optional when actually they just ought to return an empty one. So you’re completely correct in saying you should avoid optionals except when they’re necessary – it’s just a question of what necessary means. In the examples above I’d say they’re necessary, and a better solution to the alternatives.

When should I use optionals and when should I use non-optionals with default values?

The choice depends on what you model.

If a property of the object that you model may be absent completely, e.g. a middle name, a name suffix, an alternative phone number, etc., it should be modeled with an optional. A nil optional tells you that the property is not there - i.e. a person does not have a middle name or an alternative phone number. You should also use optional when you must distinguish between an empty object and a missing object.

If a property of the object must be set, and has a meaningful default, use an non-optional with a default:

class AddressList {
var addresses : [Address]
var separator : String = ";"
...
}

If users of your class need to change the separator, they have a way to do that. However, if they do not care about the separator, they can continue using the default without mentioning it in their own code.

Why NOT use optionals in Swift?

There are tons of reasons to NOT use optional. The main reason: You want to express that a value MUST be available. For example, when you open a file, you want the file name to be a string, not an optional string. Using nil as filename simply makes no sense.

I will consider two main use cases: Function arguments and function return values.

For function arguments, the following holds: If the argument needs to be provided, option should not be used. If handing in nothing is okay and a valid (documented!) input, then hand in an optional.

For function return values returning no optional is especially nice: You promise the caller that he will receive an object, not either an object or nothing. When you do not return an optional, the caller knows that he may use the value right away instead of checking for null first.

For example, consider a factory method. Such method should always return an object, so why should you use optional here? There are a lot of examples like this.

Actually, most APIs should rather use non-optionals instead of optionals. Most of the time, simply passing/receiving possibly nothing is just not what you want. There are rather few cases where nothing is an option.

Each case where optional is used must be thoroughly documented: In which circumstances will a method return nothing? When is it okay to hand nothing to a method and what will the consequences be? A lot of documentation overhead.

Then there is also conciseness: If you use an API that uses optional all over the place, your code will be cluttered with null-checks. Of course, if every use of optional is intentional, then these checks are fine and necessary. However, if the API only uses optional because its author was lazy and was simply using optional all over the place, then the checks are unnecessary and pure boilerplate.

But beware!

My answer may sound as if the concept of optionals is quite crappy. The opposite is true! By having a concept like optionals, the programmer is able to declare whether handing in/returning nothing is okay. The caller of a function is always aware of that and the compiler enforces safety. Compare that to plain old C: You could not declare whether a pointer could be null. You could add documentation comments that state whether it may be null, but such comments were not enforced by the compiler. If the caller forgot to check a return value for null, you received a segfault. With optionals you can be sure that noone dereferences a null pointer anymore.

So in conclusion, a null-safe type system is one of the major advances in modern programming languages.

nil in an optional type, what exactly is behind it? what it looks like in the memory?

With this

var john: Person?

A slot of memory is added on top of the Stack.

The type of this slot is Optional value of type Person

Optional

Inside this location of memory we found the Optional.none value.

After this

john = Person(name: "Mr Robot")

some memory is allocated into the Heap.

This memory is then written following the logic of the Person initializer.

Then let's get back to the Stack.
Here the Optional.none is replaced with the value Optional.some and the address memory of the Person object is written inside a special a field of the enum value.

Unwrap/coalesce a multi-level optional

This code does what you ask for. The drawback is that you need to implement the Unwrappable protocol in every type you want to put inside optionals. Maybe Sourcery can help with that.

protocol Unwrappable {
associatedtype T

func unwrap(_ default: T) -> T
}

extension Optional {}

extension Optional: Unwrappable where Wrapped: Unwrappable {
typealias T = Wrapped.T

func unwrap(_ defaultValue: T) -> T {
if let value = self {
return value.unwrap(defaultValue)
}
return defaultValue
}
}

extension Int: Unwrappable {
typealias T = Int

func unwrap(_ default: Int) -> Int {
return self
}
}

let nestedOptionalValue: Int??? = 6
let nestedOptionalNil: Int??? = nil
let optionalValue: Int? = 6
let optionalNil: Int? = nil
print(nestedOptionalValue.unwrap(0)) // prints 6
print(nestedOptionalNil.unwrap(0)) // prints 0
print(optionalValue.unwrap(0)) // prints 6
print(optionalNil.unwrap(0)) // prints 0

The trick is that the Unwrappable protocol marks types that can be eventually unwrapped (as in after 0, 1 or more unwraps) to a certain type.

The difficulty in this problem comes from the fact that in an extension to Optional, you can get the Wrapped type, but if Wrapped is optional again, you can't access Wrapped.Wrapped (in other words, Swift doesn't support Higher Kinded Types).

Another approach, would be to try to add an extension to Optional where Wrapped == Optional. But again you'd need Higher Kinded Types support to access the Wrapped.Wrapped type. If we try to extend Optional where Wrapped == Optional, we also fail, because we cant extend Optional generically over T.

Why are optionals useful when I can just do if(var != null)?

I think the key distinction is that Optionals allow the type system to express when something might be nil or definitely will not. In Javascript, you have no way of expressing "var x will never be undefined, so no need to add that check everywhere" and similarly, in Javascript, you may have a var that you expect to have a value, and forget to check the possibility that it is undefined in some cases.

Optionals promote this distinction into an actual type in the type system, so the compiler can detect (and warn you) when you are assuming non-nil in contexts where nil is a possibility that must be considered. And similarly, non-optional types can be enforced by the compiler to never be set to a nil value (which would violate assumptions of dependent code expecting a non-nil value).

Put differently, without Optionals, only runtime checks can determine if a value even might be nil (there is no way of knowing). In Swift, with Optionals, the type itself can specify whether nil must be considered or not, and so the compiler can verify safety at build-time, or even as you type.

Swift, Optional wrappers. ? ! I understand how it works. But why is it better than != nil checking

The difference between checking for nil and requiring an optional being unwrapped can amount to the difference between your code crashing or not. Optionals, when used correctly, can both increase safety and make your code more readable.

Suppose you have an array, and you want to get out the first value in it. You might do it like this:

if !arr.isEmpty {
useValue(arr[0])
}

But of course, it’s easy to forget that isEmpty part, and if you do, your code will crash with an out-of-bounds error.

So intead, there’s a much better way: use the array's first method, which returns an optional with nil if the array is empty:

if let val = arr.first {
useValue(val)
}

With this form, you cannot get this wrong. It’s impossible to use the arr. first value without unwrapping it. If you forget, you get a compilation error. It’s also more readable to my eyes/

Presumably you would expect your != nil formulation to work something like this:

if arr.first != nil {
// all optionals would be “implicit”
useValue(arr.first)
}

Putting aside that you’re calling .first twice which is a bit inefficient, and the question of type compatibility, essentially this lands you back to square one – you could forget to do the nil comparison, and then, kaboom. Or, you could take the Objective-C approach and say nil is fine to send messages to – but that also leads to all kinds of confusion (personally I hate the idea of an implicit sending messages to nil meaning no-op), and also leads to the question, what do you do when the function returns a value type such as an Int. Must everything be nullable? This leads to much mess in Obj-C land.

What’s more, there are all sorts of conveniences you can introduce once you are dealing with optionals, such as nil-coalescing:

// default to 0 if no first element
arr.first ?? 0
// much neater than this equivalent form:
arr.first != nil ? arr.first : 0

or optional comparison:

// will only be true if arr is non-nil and zero
if arr.first == 0 {

}

For more examples, see this answer

Swift: Early return if both optionals are nil?

That's a use-case for the nil-coalescing operator ??:

func authenticate(_account: Account?) {
if let account = _account ?? self.defaultAccount {
self.doLotsOfThings(account)
}
}

or early-return with guard:

func authenticate(_account: Account?) {
guard let account = _account ?? self.defaultAccount else {
return
}
self.doLotsOfThings(account)
}

The expression

_account ?? self.defaultAccount

evaluates to _account if _account != nil, and to
self.defaultAccount otherwise.

Also ?? is a "short-circuiting" operator like && and ||,
which means that in
your case, self.defaultAccount is not even evaluated if
_account != nil.

How to avoid returning an optional after throwing an exception?

You can use Swift assert(_:_file:line:) function as follows

assert(some condition, "Message to display if condition is false (optional)" )

If the condition is verified the app will continue running, otherwise it will terminate



Related Topics



Leave a reply



Submit