Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do Generators whose Element is Optional know when they've reached the end?

Tags:

swift

The Swift GeneratorType reference says about the next method:

next() Advance to the next element and return it, or nil if no next element exists.

And then in the discussion, it says

Requires: next() has not been applied to a copy of self since the copy was made, and no preceding call to self.next() has returned nil. Specific implementations of this protocol are encouraged to respond to violations of this requirement by calling preconditionFailure("...").

If the Generator is for an Optional type, then it is possible for it to reach a nil value before reaching the end of the sequence. How does Swift know that it has not reached the end in this case?

like image 540
BallpointBen Avatar asked Feb 07 '23 09:02

BallpointBen


1 Answers

It's important to note that whatever type a generator is generating, it wraps that type in an optional.

The GeneratorType protocol declares an associated type which it calls Element and a method, next(), whose return type is of type Element?. Whatever Element is, next() wraps it in an optional (and remember, optional is just an enum).

So a generator generating optionals wraps those optionals in another optional layer.

Consider the following:

let array: [Int?] = [1, 2, nil, 4, nil, nil, 7, 8, nil, nil, 11]

This is an array of optional integers.

So if we call generate() on this array, it will give us something that returns type Optional<Optional<Int>> or Int?? from the next() method.

enter image description here

The first two calls to next will give us values (1, then 2). The third looks like it returns nil:

enter image description here

But effectively this is just misleading information. Realistically, the third return is actually this: Optional.Some(nil)

We can see that there are more values to generate by looking at this while loop, which is terminated by the real nil that is generated after 11:

enter image description here

All of the nil values we see print are actually Optional.Some(nil), and when the next() call finally returns Optional.None, the loop terminates.

What we're looking at here is the difference between the following three values possible values:

let optionalSomeValue: Int?? = 3
let optionalSomeNil: Int?? = Optional.Some(nil)
let optionalReallyNil: Int?? = nil

Note that the second line could also be written as:

let optionalSomeNil: Int?? = Optional.Some(Optional.None)

At the end of the day, we have to keep in mind that optional is just a generic enum:

enum Optional<T> {
    case Some(T)
    case None
}

There is no restriction on what T can be, which means it can itself be an optional, and it could be an optional with case None.

In Swift, the nil keyword is just a convenient shortcut for Optional<T>.None and the ? syntax for declaring optionals is likewise a convenient shortcut for Optional<T>.Some. Consider that the following two lines are equivalent in every manner except the variable name:

let foo = Optional<Int>.None
let bar: Int? = nil

enter image description here

like image 67
nhgrif Avatar answered May 20 '23 22:05

nhgrif