In Swift I can declare a constant of type Any
and put a String
into it.
let any: Any = "hello world"
Good. On the other hand I cannot put a nil
value into any
because it's not optional.
let any: Any = nil error: nil cannot initialize specified type 'Any' (aka 'protocol<>') let any: Any = nil ^
Perfect. But why does the compiler allow me do write the following code?
let couldBeNil: String? = nil let any: Any = couldBeNil print(any) // nil
Doesn't Any
follow the Swift rule that only an Optional var/let can be populated with nil
?
Tested with Xcode Playground 7.2 + Swift 2.1.1
Swift assumes by default that all variables have a value. Unless you tell it otherwise by declaring an optional you can't have a nil value in a place where your program expects there to be a value. In this example, our function expects its name parameter to have a value.
Question : What's the difference optional between nil and . None? Answer : There is no difference.
Any data type can be optional in Swift: An integer might be 0, -1, 500, or any other range of numbers. An optional integer might be all the regular integer values, but also might be nil – it might not exist.
Nil-coalescing operator In Swift, you can also use nil-coalescing operator to check whether a optional contains a value or not. It is defined as (a ?? b) . It unwraps an optional a and returns it if it contains a value, or returns a default value b if a is nil.
TL;DR; Optionals in swift are translated by the compiler to Optional
enum instances, and since Any
can map to any value, it can be used to store optionals.
How does Swift represent optionals? It does it by mapping SomeType?
to a concrete implementation of the Optional
enum:
Int? => Optional<Int> String? => Optional<String>
A simplified declaration of Optional
looks like this:
enum Optional<T> { case none // nil case some(T) // non-nil }
Now, a variable of type Any
is able to hold an enum value (or any other kind of value, or even metatype information), so it should be able to hold for example a nil
String, aka String?.none
, aka Optional<String>.none
.
Let's see what happens, though. As we see by the Optional
declaration, nil
corresponds to the .none
enum case for all types:
nil == Optional<String>.none // true nil == Optional<Int>.none // true [Double]?.none == nil // also true
So theoretically, you should be able to assign nil
to a variable declared as Any
. Still, the compiler doesn't allow this.
But why doesn't the compiler let you assign nil
to an Any
variable? It's because it can't infer to which type to map the .none
enum case. Optional
is a generic enum, thus it needs something to fill the T
generic parameter, and plain nil
is too broad. Which .none
value should it use? The one from Int
, the one from String
, another one?
This gives an error message supporting the above paragraph:
let nilAny: Any = nil // error: nil cannot initialize specified type 'Any' (aka 'protocol<>')
The following code works, and is equivalent to assigning a nil
:
let nilAny: Any = Optional<Int>.none
, as the above Any
variable is actually holding a valid value of the Optional
enum.
Indirect assignments work too, as behind the scenes nil
is converted to Optional<Type>.none
.
var nilableBool: Bool? // nilableBool has the Optional<Bool>.none value var nilBoolAsAny: Any = nilableBool // the compiler has all the needed type information from nilableBool
Unlike other languages, in Swift nil
corresponds to a concrete value. But it needs a type to work with, for the compiler to know which Optional<T>.none
it should allocate. We can think of the keyword as providing sugar syntax.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With