# Casting from Any to Optional

**URL:** <https://forums.swift.org/t/casting-from-any-to-optional/21883>\
**Category:** Discussion\
**Created:** [March 21, 2019, 3:16pm UTC](https://forums.swift.org/t/casting-from-any-to-optional/21883 "2019-03-21T15:16:33Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![Nevin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nevin/32/617_2.png) [@Nevin](https://forums.swift.org/u/Nevin)\
**Post date:** [March 21, 2019, 3:16pm UTC](https://forums.swift.org/t/casting-from-any-to-optional/21883/1 "2019-03-21T15:16:33Z")

</div>

Currently (in Swift 4.2.1), it is an error to cast a value from `Any` to `Optional`, even when that value was created as the exact same `Optional` type and previously cast to `Any`. Here is an example:

```swift
let x: Int? = 1
let y: Any = x as Any
print(type(of: y)) // "Optional<Int>\n"

let z: Int? = y as! Int? // error: cannot downcast from 'Any' to a more optional type 'Int?'

```

Is this a bug, or an oversight, or an intentional design decision? In particular, would it require an evolution proposal to make it possible for this to work? My expectation was that `Any` could wrap _any_ type, and be unwrapped back to that type.

So far the only way I have found to extract the original `Optional` value, is via a generic helper function such as:

```swift
func unwrap<T>(_ x: Any) -> T {
  return x as! T
}

let z: Int? = unwrap(y)
print(type(of: z)) // "Optional<Int>\n"

```

It seems rather peculiar that we can attempt to unwrap an `Any` into an unspecified generic type, but we are prohibited from unwrapping an `Any` into the exact specific type we know it contains, if that type is `Optional`.

---

<div class="post-metadata">

**Author:** ![sharplet](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/sharplet/32/6184_2.png) [@sharplet](https://forums.swift.org/u/sharplet)\
**Post date:** [March 21, 2019, 3:30pm UTC](https://forums.swift.org/t/casting-from-any-to-optional/21883/2 "2019-03-21T15:30:05Z")

</div>

I agree that this feels like an arbitrary limitation, especially given that this works exactly as expected:

```swift
let maybeInt = 1 as Int?
let anything = maybeInt as Any

let opened = anything as? Int?
// error: cannot downcast from 'Any' to a more optional type 'Int?'

func dynamicCast<T>(_ value: Any, to _: T.Type) -> T? {
  if let value = value as? T {
    return value
  } else {
    return nil
  }
}

if let opened = dynamicCast(anything, to: Int?.self) {
  print("got an optional Int: \(opened)")
} else {
  print("it's something else entirely")
}

```

---

<div class="post-metadata">

**Author:** ![jrose](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jrose/32/408_2.png) [@jrose](https://forums.swift.org/u/jrose)\
**Post date:** [March 21, 2019, 6:28pm UTC](https://forums.swift.org/t/casting-from-any-to-optional/21883/3 "2019-03-21T18:28:06Z")

</div>

I think we added this to stop people from expecting `x as! Int?` to act like `x as? Int`. It's not really a correct error when casting from any (non-class) existential / protocol value (`Any` is "no protocols").

---

<div class="post-metadata">

**Author:** ![hisekaldma](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/hisekaldma/32/1146_2.png) [@hisekaldma](https://forums.swift.org/u/hisekaldma)\
**Post date:** [March 21, 2019, 8:44pm UTC](https://forums.swift.org/t/casting-from-any-to-optional/21883/4 "2019-03-21T20:44:00Z")

</div>

> [@jrose](#):
>
> I think we added this to stop people from expecting `x as! Int?` to act like `x as? Int`.

Could you elaborate? I run into the error described here multiple times, but I've never tried to do `x as! Int?` instead of `x as? Int`. Why would someone think that they're the same?

---

<div class="post-metadata">

**Author:** ![jrose](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jrose/32/408_2.png) [@jrose](https://forums.swift.org/u/jrose)\
**Post date:** [March 21, 2019, 8:50pm UTC](https://forums.swift.org/t/casting-from-any-to-optional/21883/5 "2019-03-21T20:50:01Z")

</div>

:-/ I don't have much here, but I remember it coming up in the first few years of Swift. It's also logic shared with `x as? Int?`, which is a more reasonable typo to make (because you want the result type to be optional). The compiler could certainly make a different decision about diagnosis based on `as?` vs. `as!`.

---

<div class="post-metadata">

**Author:** ![phlegmaticprogrammer](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/phlegmaticprogrammer/32/11253_2.png) [@phlegmaticprogrammer](https://forums.swift.org/u/phlegmaticprogrammer)\
**Post date:** [December 22, 2019, 11:36am UTC](https://forums.swift.org/t/casting-from-any-to-optional/21883/6 "2019-12-22T11:36:48Z")

</div>

I needed some code to test if an `Any` is nil, which I thanks to this thread managed:

```
func isNil(_ x : Any) -> Bool {
    func unwrap<T>() -> T {
        return x as! T
    }
    let y : Any? = unwrap()
    return y == nil
}

```

Is there a less convoluted way of achieving this?

---

<div class="post-metadata">

**Author:** ![mattpolzin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mattpolzin/32/6041_2.png) [@mattpolzin](https://forums.swift.org/u/mattpolzin)\
**Post date:** [December 22, 2019, 5:48pm UTC](https://forums.swift.org/t/casting-from-any-to-optional/21883/7 "2019-12-22T17:48:26Z")

</div>

> [@phlegmaticprogrammer](#):
>
> Is there a less convoluted way of achieving this?

There is no light-weight built-in way of doing this, but a common approach that just might meet your criteria for convolution is to use a custom protocol (often scoped `internal` or even `fileprivate`).

```swift
protocol _Optional {
    var isNil: Bool { get }
}

extension Optional: _Optional {
    var isNil: Bool { return self == nil }
}

func isNil (_ input: Any) -> Bool {
    return (input as? _Optional)?.isNil ?? false
}

isNil(nil as String?) // true
isNil("") // false

```

---

<div class="post-metadata">

**Author:** ![jeremyabannister](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jeremyabannister/32/10143_2.png) [@jeremyabannister](https://forums.swift.org/u/jeremyabannister)\
**Post date:** [November 27, 2020, 12:57am UTC](https://forums.swift.org/t/casting-from-any-to-optional/21883/8 "2020-11-27T00:57:58Z")

</div>

> [@jrose](#):
>
> It's not really a correct error when casting from any

I too just ran into this error trying to cast `Any` as an optional and would have liked for it to work, so I just wanted to add my vote for allowing casting from `Any` to `Optional<SomeType>` if there's no harm in it.

To be more specific, what I want is that when I have a value of type `Any` I can distinguish between `nil` of different types:

```swift
let nilInt: Int? = nil
let nilString: String? = nil

func isNilString (_ value: Any) -> Bool {
    guard let optionalString = value as? String? else { return false }
    return optionalString == nil
}

isNilString(nilInt) // Should return false
isNilString(nilString) // Should return true

```

---

<div class="post-metadata">

**Author:** ![anassalzurba](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/anassalzurba/32/15905_2.png) [@anassalzurba](https://forums.swift.org/u/anassalzurba)\
**Post date:** [April 1, 2021, 10:39am UTC](https://forums.swift.org/t/casting-from-any-to-optional/21883/9 "2021-04-01T10:39:07Z")

</div>

Any updates here? Who can we talk to to get this going?

maybe we could allow `as Optional<T>` but not `as T?` or to allow `as (T?)`. just to make sure the user knows what they are doing.

---

<div class="post-metadata">

**Author:** ![xAlien95](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/xalien95/32/12558_2.png) [@xAlien95](https://forums.swift.org/u/xAlien95)\
**Post date:** [April 1, 2021, 1:51pm UTC](https://forums.swift.org/t/casting-from-any-to-optional/21883/10 "2021-04-01T13:51:32Z")

</div>

You can currently do a double cast if you want:

```swift
let x = Int?.some(3) as Any

if let xx = x as Any? as? Int? {
  // here 'xx' is 'Int?'
}

```

---

<div class="post-metadata">

**Author:** ![young](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/young/32/7878_2.png) [@young](https://forums.swift.org/u/young)\
**Post date:** [April 1, 2021, 6:40pm UTC](https://forums.swift.org/t/casting-from-any-to-optional/21883/11 "2021-04-01T18:40:33Z")

</div>

Works in Xcode Version 12.5 beta 3 (12E5244e)

z is back to `Optional(1)`

---

<div class="post-metadata">

**Author:** ![Nobody1707](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nobody1707/32/2169_2.png) [@Nobody1707](https://forums.swift.org/u/Nobody1707)\
**Post date:** [April 1, 2021, 11:01pm UTC](https://forums.swift.org/t/casting-from-any-to-optional/21883/12 "2021-04-01T23:01:46Z")

</div>

You can always add a failable initializer to Optional that does the conversion:

```swift
let x: Int? = 1
let y: Any = x as Any
print(type(of: y)) // "Optional<Int>\n"

extension Optional {
    init?(from any: Any) {
        guard let opt = any as Any? as? Self else {
            return nil
        }
        self = opt
    }
}

let z: Int? = Optional(from: y)!

```

---

<div class="post-metadata">

**Author:** ![xAlien95](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/xalien95/32/12558_2.png) [@xAlien95](https://forums.swift.org/u/xAlien95)\
**Post date:** [April 1, 2021, 11:07pm UTC](https://forums.swift.org/t/casting-from-any-to-optional/21883/13 "2021-04-01T23:07:16Z")

</div>

Nice find! Yes, with Swift 5.4 we can now cast from `Any` to `T?` without intermediate steps.

---

<div class="post-metadata">

**Author:** ![Nobody1707](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nobody1707/32/2169_2.png) [@Nobody1707](https://forums.swift.org/u/Nobody1707)\
**Post date:** [April 1, 2021, 11:08pm UTC](https://forums.swift.org/t/casting-from-any-to-optional/21883/14 "2021-04-01T23:08:15Z")

</div>

That's good. Does anyone know why it wasn't working before?
