Do Optionals Default to Nil

Do Optionals default to nil?

Yes it is automatically set to nil if unassigned.

From Apple:

If you define an optional variable without providing a default value,
the variable is automatically set to nil for you

Constant unassigned optional will not be nil by default

Yes it's correct

An optional variable doesn't need to be manually initialized. If you read it before having populated it does contain nil.

From Apple docs

If you define an optional variable without providing a default value, the variable is automatically set to nil for you [...]

On the other hand the compiler does force you to manually initialize an Optional constant (let) before you can read it.

Unlike a variable, the value of a constant cannot be changed once it is set. Attempting to do so is reported as an error when your code is compiled [...]

Why?

A constant can be written only once. It doesn't need to happened on the same line it is initialized but it must happened before your read it.

E.g. this code works fine

let num: Int?
num = 1
print(num)

However if the compiler had put a temporary nil value inside num then the constant would have been wrote twice. Which is against the concept of constant.

let num: Int?
print(num) // nil ??? <- this can't work!
num = 1
print(num) // 1

Another example

This code snippet works fine

func printArea(width: Int?, height:Int?) {
let area: Int?
if let width = width, height = height {
area = width * height
} else {
area = nil
}
print(area)
}

Again, if the compiler had put a temporary nil value inside area then...

func printArea(width: Int?, height:Int?) {
let area: Int?
print(area) // not possible! area is going to change in a moment
if let width = width, height = height {
area = width * height
} else {
area = nil
}
print(area)
}

Why optional constant does not automatically have a default value of nil

Not setting a read-only (constant) field with either an:

  • initialization expression
  • initializer

is almost certainly an indication of an error in your program.

Since you have no other opportunity to set the value of your let field, the value of the field is going to remain nil (or some other default). It is rather unlikely that a programmer would find such behavior desirable, and request it on purpose.

That is why Swift marks this situation as an error. On the other hand, if you actually wanted your String constant to remain nil, you could add an expression to set it to nil, and silence the error:

let owner: String? = nil // Pretty useless, but allowed

How to disable default nil-initialization of Optional

If your var's type is written T? with no default value, and Swift synthesizes a memberwise init for your type, then the synthesized init uses a default value of nil for that var.

However, if your var's type is written Optional<T> with no default value, then the synthesized init does not use a default value.

So write this instead:

struct DataOne {
let id: String
var name: Optional<String>
// ...
}

struct DataTwo {
let id: String
var name: Optional<String>
// ...
}

Or write out your init instead of letting the compiler synthesize it:

struct DataOne {
let id: String
var name: String?

init(id: String, name: String?) {
self.id = id
self.name = name
}
}

struct DataTwo {
let id: String
var name: String?

init(id: String, name: String?) {
self.id = id
self.name = name
}
}

You can use Xcode's Editor > Refactor > Generate Memberwise Initializer command to write most of the init for you, then delete the = nil default:

demonstration of using Generate Memberwise Initializer

No need for initializer for optional properties inside Swift class

Optional Property Types :

If your custom type has a stored property that is logically allowed to have “no value”—perhaps because its value cannot be set during initialization, or because it is allowed to have “no value” at some later point—declare the property with an optional type. Properties of optional type are automatically initialized with a value of nil, indicating that the property is deliberately intended to have “no value yet” during initialization.

For Example :

class SurveyQuestion {
var text: String?
init(text: String) {
self.text = text
}
func ask() {
print(text)
}
}

let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")
cheeseQuestion.ask()
// Prints "Do you like cheese?"
let cheeseQuestion1 = SurveyQuestion()
cheeseQuestion.ask()
// Prints nil

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.

Providing a default value for an Optional in Swift?

Update

Apple has now added a coalescing operator:

var unwrappedValue = optionalValue ?? defaultValue

The ternary operator is your friend in this case

var unwrappedValue = optionalValue ? optionalValue! : defaultValue

You could also provide your own extension for the Optional enum:

extension Optional {
func or(defaultValue: T) -> T {
switch(self) {
case .None:
return defaultValue
case .Some(let value):
return value
}
}
}

Then you can just do:

optionalValue.or(defaultValue)

However, I recommend sticking to the ternary operator as other developers will understand that much more quickly without having to investigate the or method

Note: I started a module to add common helpers like this or on Optional to swift.

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<Person>

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.



Related Topics



Leave a reply



Submit