What you're seeing here is a result of "Optional
promotion" in Swift: if a function takes a value of type T?
and you try to pass a value of type T
to it, Swift will implicitly wrap your value in .some
in order to convert it to the right type. This includes static func ==(...)
.
Although Any
is allowed to contain a nil
value despite not being an Optional
, Swift's Optional
promotion rules still apply to it; this means that when you write any == nil
, Swift still promotes any: Any
to .some(any): Any?
in order to compare against nil
. In this case, .some(any)
is not nil
, hence the false
results.
If you try to compile this code outside of a playground, you'll get warnings letting you know that this is about to happen:
/main.swift:2:16: warning: expression implicitly coerced from 'String?' to 'Any'
var any: Any = optional // nil
^~~~~~~~
/main.swift:2:16: note: provide a default value to avoid this warning
var any: Any = optional // nil
^~~~~~~~
?? <#default value#>
/main.swift:2:16: note: force-unwrap the value to avoid this warning
var any: Any = optional // nil
^~~~~~~~
!
/main.swift:2:16: note: explicitly cast to 'Any' with 'as Any' to silence this warning
var any: Any = optional // nil
^~~~~~~~
as Any
/main.swift:5:17: warning: comparing non-optional value of type 'Any' to 'nil' always returns false
debugPrint( any == nil ? "true" : "false" ) // print "false"
~~~ ^ ~~~
One way to get the Optional
ity back is to force-cast any
to an Optional
:
debugPrint(any as! Any? == nil ? "true" : "false") // "true"
Unfortunately, you will get an unsilenceable warning informing you that this cast will always succeed.
See Any should never be nil and similar threads here on the forums for more info.
In general, because of this, if you know that your value may be Optional
, it's significantly more ergonomic to work with Any?
over Any
.