3

Here's some strange behavior, I have a value of type Any and I wish to switch on it's protocol conformance, and when the real type of the value is optional, it does not work:

let something: Int? = 42

switch something {
case let x as Equatable: print("Yeepee! The answer is \(x)") // Here's what is matched
default: print("Boohoo!") 
}

let anything: Any = something // anything contains a Int? value

switch anything {
case let x as Equatable: print("Yeepee! The answer is \(x)")
default: print("Boohoo!")  // Here's what is matched
}

First I simply do not understand why the behavior is different, then how can I make the second switch match correctly the value, even if it's optional?

Thanks in advance.

Zaphod
  • 6,758
  • 3
  • 40
  • 60
  • Related: http://stackoverflow.com/a/27997724/5475238 – Yury Oct 11 '16 at 11:58
  • Thank you, but unfortunately it uses reflexion API, which is currently intended to be used by Playground or debugger internally, not for production code. Moreover, the `reflect` function is not available in *Swift 3*. – Zaphod Oct 11 '16 at 12:15
  • 1
    Yeah, this is really great example (one of the canonical examples in fact) of why `Any` is such a horrible type in Swift and needs to be limited as much as possible. Basically, this is a case of "if you need this, you're on the wrong road." Swift blows up constantly when faced w/ `Any` (and to a only slightly lesser extent when faced with `AnyObject`), and one of the the most subtle and pervasive versions of blowing up is when it interacts with Optional promotion to do all kinds of things you didn't expect. – Rob Napier Oct 11 '16 at 12:48

1 Answers1

0

Thanks to @Shadow, I came up with this solution, but as I said it uses reflexion API which is not intended for production, but more for Playground or debugger:

func forceUnwrap(any:Any) -> Any {
    let mirror = Mirror(reflecting: any)

    if mirror.displayStyle != .optional {
        return any
    }

    if mirror.children.count == 0 {
        return NSNull()
    }

    let (_, some) = mirror.children.first!

    return forceUnwrap(any: some)
}

switch forceUnwrap(any:anything) {
case let x as Equatable: print("Yeepee! \(x)")
default: print("Boohoo!")
}

But if someone has a solution NOT using reflexion API, I'd be grateful.

Zaphod
  • 6,758
  • 3
  • 40
  • 60