13

Apple seems to claim that the Optional type in Swift is safer than nil in Objective-C, but I don't understand why this is so.

What are the salient differences in implementation that make Optionals safer than nil, and how will this affect my code?

jscs
  • 63,694
  • 13
  • 151
  • 195
Pratap Vhatkar
  • 691
  • 10
  • 21
  • 10
    Swift does not support nil outside the use of Optional. An Optional can contain nil, whereas a non-Optional cannot contain nil. If you declare a variable as implicitly unwrapped using "!", if the variable contains nil when you make use of it, you will get an exception. Therefore you don't have to deal with a variable "magically" containing nil when you don't expect it. – Michael Feb 22 '16 at 05:19
  • 1
    @Michael Your comment works as an answer. – Dmitri Pavlutin Feb 22 '16 at 06:53

4 Answers4

2

I always do check if a variable is nil before I use it to avoid problems. However, it still happens once in a while that a value might come in as nil, to my surprise -- or sometimes I just plain forget to check.

After I code more and more in Swift, I have found that using optional variables indeed provides a lot of convenience to avoid ignoring the checking for nil values. I don't really recall any crashes due to nil variable access (unless I force the unwrapping of some variable; so don't do force unwrapping unless you know what you are doing).

Besides, I used to write a lot of code like this in many places:

if (obj != nil) {
    obj.property = ...
}

Now I can simply do it as

 obj?.property = ...

The code now looks clean and sharp. Don't you like it too?

jscs
  • 63,694
  • 13
  • 151
  • 195
Joe Huang
  • 6,296
  • 7
  • 48
  • 81
  • 1
    That's a pretty bad example, because obj.property = ... works just fine in Objective-C and does nothing. – gnasher729 Jul 10 '17 at 16:46
  • I am not referring to Objective-C. It's just a general case for most of the programming languages. Try this in Lua, for example. Crash! – Joe Huang Jul 11 '17 at 12:54
  • This question had been changed. When I answered this question, I think the question didn't mention about Objective-C's nil or to compare Swift with Objective-C. This question must be merged or changed. It has lost the original intention. – Joe Huang Oct 11 '17 at 08:09
2

It becomes "safe" because it forces the programmer to write more explicit code.

  • The if let ... and guard syntax explicitly says "do this only if there are values for these variables".
  • The ! syntax makes the program crash if the variable is nil when the programmer did not expect it to be nil.

In contrast, Objective-C's way of making calls to nil a no-op may let the program continue to execute until such point that nil is not acceptable. One common example is nil NSString variables. Many API calls are happy with a nil NSString except when constructing NSAttributedString (it won't accept a nil NSString parameter and crashed your app). Hence when you get an NSString variable unexpectedly becomes nil, it may be a while later until your app crashes because it tries to construct an attributed string with that nil value.

For a more complete illustration on the problem that Optionals tried to solve, consider this post back from 2010 by Daniel Jalkut. This was written long before Swift.

adib
  • 8,285
  • 6
  • 52
  • 91
2

In general, in programming we want to avoid variables that have no value (null or nil) because using them often results in undefined behaviour (exceptions, errors, crashes).

For example, it is a common practice for Array references to be set to empty arrays instead of nil. On an empty array we can use all the Array methods, e.g. indexOf or count. Using them on nil would result in a crash.

Optionals allow us to specify that some variables are never empty, therefore we can use them safely and the compiler checks that nil is never assigned to them. Also, the compiler enforces that every conversion from optionals to non-optionals is explicit (we are always checking for nil when needed).

So the answer would be that optionals:

  1. Enforce good programming practices.
  2. Allow for better code checking at compilation time

Thus preventing programming errors.

Also note that the you should always try to avoid optionals when possible. The greatest power of optionals is the fact that most variables are not optionals.

Sulthan
  • 128,090
  • 22
  • 218
  • 270
  • Could you elaborate your last statement "The greatest power of optionals is the fact that most variables are not optionals."? – Joe Huang Feb 22 '16 at 08:04
  • @JoeHuang That's pretty simple. If all your variables are optionals, you are back in the world without optionals. Everything can be `nil`. The power of optionals is to limit `nil` to specific libraries. – Sulthan Feb 22 '16 at 16:09
  • I do think there are more optionals when considering asynchronised programming. I don't get how to make most variables not optionals. – Joe Huang Feb 22 '16 at 16:44
  • @JoeHuang Asynchronous programming doesn't have more optionals. It's all about the programming style. Of course, you cannot avoid optionals completely but you should try to minimize their usage, otherwise you are not gaining anything from them. – Sulthan Feb 22 '16 at 17:07
  • "Using _[`indexOfObject:` or `count`]_ on `nil` would result in a crash" Well, not in ObjC. – jscs Jul 10 '17 at 16:30
  • Comparing Objective-C and Swift: Calling array methods on a nil array in Objective-C does _not_ crash. indexOfObject returns 0. count returns 0. And so on. – gnasher729 Jul 10 '17 at 16:48
  • @JoshCaswell In Obj-C the call won't crash but the result will still be unexpected. For example, `[nil indexOfObject:x]` won't return `NSNotFound`. That was the point I was trying to make. There are some situations when the language is lucky, e.g. `string.length == 0` or `array.count == 0` but there are many situations when the app won't crash but it will result in an unexpected state. One of the most common Obj-C questions on SO: *"My method is not called."*. – Sulthan Jul 10 '17 at 17:56
-2

In Objective-C, you can define a variable without a value. If you want to use that variable before assigning a value, you will get a undefined behaviour(which is very bad). On contrary, swift prevents the scenario where the value of a object is unknown.

Joey Yi Zhao
  • 37,514
  • 71
  • 268
  • 523
  • 1
    Since ARC was introduced a few years ago, any pointer to an Objective-C object is automatically initialised to nil. No undefined behaviour. And if you turn on reasonable compilation settings, your code will not compile if you try to use an uninitialised variable. – gnasher729 Jul 10 '17 at 16:45