# Challenge: Finding base type of nested optionals

**URL:** <https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096>\
**Category:** Using Swift\
**Created:** [June 1, 2019, 8:43am UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096 "2019-06-01T08:43:41Z")\
**Posts on this page:** 20\
**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:** [June 1, 2019, 8:43am UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/1 "2019-06-01T08:43:41Z")

</div>

Following on from my [last challenge](https://forums.swift.org/t/challenge-flattening-nested-optionals/24083), this one is somewhat trickier:

Given an arbitrarily-nested `Optional`, the goal is to programmatically identify the inner-most `Wrapped` type (aka. its base type). Note that the optional may be nil at any depth, and it may be wrapped in further layers of `Any` and/or `Optional`.

For example, an `Int???` has a base type of `Int`, regardless of its value. Moreover, casting an `Optional` to `Any`, and/or wrapping it in additional layers of `Optional`, does not change its base type.

Can you write such a function?

The signature should be:

```swift
extension Optional {
  func baseType() -> Any.Type
}

```

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [June 1, 2019, 9:43am UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/2 "2019-06-01T09:43:03Z")

</div>

```swift
fileprivate protocol Wrapper {
  static func baseType() -> Any.Type
  func baseType() -> Any.Type
}

extension Optional: Wrapper {
  static func baseType() -> Any.Type {
    var type: Any.Type = Wrapped.self
    while let wrapper = type as? Wrapper.Type {
      type = wrapper.baseType()
    }
    return type
  }

  func baseType() -> Any.Type {
    var base: Any.Type
    switch self {
    case .some(let value):
      if let wrapper = value as? Wrapper {
        base = wrapper.baseType()
      } else {
        base = Wrapped.self
      }
    case .none:
      base = Wrapped.self
    }
    if let wrapper = base as? Wrapper.Type {
      base = wrapper.baseType()
    }
    return base
  }
}

```

I think this works now. It will unwrap the value as much as possible and at the end we will also try to check the wrapper type if needed.

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [June 1, 2019, 6:11pm UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/3 "2019-06-01T18:11:41Z")

</div>

@Nevin please do more challenges 🙂 Also we need a way to verify the solutions (I‘m not sure if I covered all possible cases).

---

<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:** [June 1, 2019, 7:08pm UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/4 "2019-06-01T19:08:35Z")

</div>

Well done! That is rather more elegant than the solution I had in mind, which involved two procotols.

> [@DevAndArtist](#):
>
> Also we need a way to verify the solutions (I‘m not sure if I covered all possible cases).

Here’s what I’ve been using to test:

> **Testing for base type**
>
> ```swift
> // Creating obnoxiously-wrapped optionals for testing
> 
> func deeplyWrap<T>(_ x: T?) -> Any? {
> switch Int.random(in: 0..<10) {
> case 0: return x as Any
> case 1..<4: return deeplyWrap(x as Any)
> default: return deeplyWrap(Optional(x))
> }
> }
> 
> // Testing the implementation of Optional.baseType
> 
> func testBaseType<T>(_ x: T?) -> [Any.Type] {
> let a: T? = x
> let b: T?? = Optional(a)
> let c: T??? = Optional(b)
> let d: Any? = Optional(c as Any)
> let e: Any? = Optional(d as Any)
> let f: Any??? = Optional(Optional(e))
> let g: Any? = Optional(f as Any)
>   
> // Do not try to use `map` here like this:
> //
> // let results = [a, b, c, d, e, f, g].map{ $0.baseType() }
> //
> // It will not work because the types of a...g are different
> // and weird things happen when eg. T?? is coerced to Any???
>   
> let results = [a.baseType(),
> b.baseType(),
> c.baseType(),
> d.baseType(),
> e.baseType(),
> f.baseType(),
> g.baseType()]
>   
> print(results.map{"\($0)"}.joined(separator: " "))
>   
> return results
> }
> 
> // Actually calling the tests
> 
> do {
> testBaseType(nil as Int?)
> testBaseType("2" as String???)
> testBaseType(nil as Int??)
> testBaseType("a")
> testBaseType(2)
>   
> let q = deeplyWrap(nil as String????)
> print()
> print(type(of: q))
> print(q.debugDescription)
> testBaseType(q)
>   
> let q2 = deeplyWrap(4 as Int????)
> print()
> print(type(of: q2))
> print(q2.debugDescription)
> testBaseType(q2)
> }
> 
> ```

---

<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:** [June 1, 2019, 10:39pm UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/5 "2019-06-01T22:39:59Z")

</div>

I was able to simplify your second function a bit:

```swift
  func baseType() -> Any.Type {
    if case .some(let value as Wrapper) = self {
      return value.baseType()
    }
    if let wrapper = Wrapped.self as? Wrapper.Type {
      return wrapper.baseType()
    }
    return Wrapped.self
  }

```

And, not sure if it counts as “simpler”, but I also shortened your static function by one line:

```swift
  static func baseType() -> Any.Type {
    if let wrapper = Wrapped.self as? Wrapper.Type {
      return wrapper.baseType()
    }
    return Wrapped.self
  }

```

• • •

Edit:

Actually, they can be reduced even further with optional chaining and nil-coalescing:

```swift
extension Optional: Wrapper {
  static func baseType() -> Any.Type {
    return (Wrapped.self as? Wrapper.Type)?.baseType() ?? Wrapped.self
  }
  
  func baseType() -> Any.Type {
    if case .some(let value as Wrapper) = self {
      return value.baseType()
    }
    return Wrapped?.baseType()
  }
}

```

This is _way_ nicer than the solution I had come up with on my own!

• • •

Edit 2:

Shortened the last line of the non-static method, for DRYness. (It had been identical to the body of the static method.) Once SE–68 is available (in Swift 5.1), it can even become “`return Self.baseType()`”.

---

<div class="post-metadata">

**Author:** ![kansaichris](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/kansaichris/32/2703_2.png) [@kansaichris](https://forums.swift.org/u/kansaichris)\
**Post date:** [June 3, 2019, 6:22am UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/6 "2019-06-03T06:22:48Z")

</div>

So while reading through and experimenting with this code to truly understand how it works, I came across what (to me) was some surprising behavior.

Consider the following sample code, which uses @Nevin's concise extension from above:

```swift
let wrappedInt: Int? = 7
let doublyWrappedInt: Any?? = Optional(wrappedInt as Any)

type(of: doublyWrappedInt) // Optional<Optional<Any>>.Type

doublyWrappedInt.baseType() // Int.Type

```

No real surprises here. Now let's just change that second line slightly…

```swift
let wrappedInt: Int? = 7
let doublyWrappedInt: Any?? = wrappedInt

type(of: doublyWrappedInt) // Optional<Optional<Any>>.Type

doublyWrappedInt.baseType() // Any.Protocol

```

Why is it that even though `type(of: doublyWrappedInt)` still returns `Optional<Optional<Any>>`, `baseType()` now returns `Any.Protocol` instead of `Int.Type`?

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [June 3, 2019, 7:56am UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/7 "2019-06-03T07:56:42Z")

</div>

If you take my original example and put some print logs to trace where the algorithm goes you can find out the issue here:

```swift
extension Optional: Wrapper {
  static func baseType() -> Any.Type {
    print("6")
    var type: Any.Type = Wrapped.self
    while let wrapper = type as? Wrapper.Type {
      print("7")
      type = wrapper.baseType()
    }
    return type
  }

  func baseType() -> Any.Type {
    var base: Any.Type
    switch self {
    case .some(let value):
      print("1", type(of: value), value)
      if let wrapper = value as? Wrapper {
        print("2")
        base = wrapper.baseType()
      } else {
        print("3")
        base = Wrapped.self // should be `type(of: value)`
      }
    case .none:
      print("4")
      base = Wrapped.self 
    }
    if let wrapper = base as? Wrapper.Type {
      print("5")
      base = wrapper.baseType()
    }
    return base
  }
}

```

The result is:

```swift
1 Optional<Any> Optional(7)
2
1 Any 7 // this could be a compiler bug?
3

```

That means that in the line `let doublyWrappedInt: Any?? = wrappedInt` there is an implicit conversion from `Optional<Int>` to `Optional<Any>`. At this case I think the algorithm must be adjusted. Instead of `base = Wrapped.self` we should use `base = type(of: value)`. If we do that the result remains the same as already noted above `type(of: value)` does not return `Int` but `Any` which feels like a bug.

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [June 3, 2019, 8:05am UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/8 "2019-06-03T08:05:26Z")

</div>

@Nevin I would rewrite my original solution to this:

```swift
fileprivate protocol Wrapper {
  static func baseType() -> Any.Type
  func baseType() -> Any.Type
}

extension Optional: Wrapper {
  fileprivate static func baseType() -> Any.Type {
    switch Wrapped.self {
    case let wrapper as Wrapper.Type:
      return wrapper.baseType()
    default:
      return Wrapped.self
    }
  }

  func baseType() -> Any.Type {
    switch self {
    case .some(let wrapper as Wrapper):
      return wrapper.baseType()
    case .some(let wrapped):
      return type(of: wrapped)
    case .none:
      return Optional.baseType()
    }
  }
}

```

---

<div class="post-metadata">

**Author:** ![kansaichris](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/kansaichris/32/2703_2.png) [@kansaichris](https://forums.swift.org/u/kansaichris)\
**Post date:** [June 3, 2019, 8:13am UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/9 "2019-06-03T08:13:26Z")

</div>

> [@DevAndArtist](#):
>
> That means that in the line `let doublyWrappedInt: Any?? = wrappedInt` there is an implicit conversion from `Optional<Int>` to `Optional<Any>` .

Interesting. If that's the case, why doesn't `Optional(wrappedInt as Any)` also involve a conversion from `Optional<Int>` to `Optional<Any>`?

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [June 3, 2019, 8:18am UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/10 "2019-06-03T08:18:56Z")

</div>

I can only guess, but I'd think that this example is a little different. `Optional(wrappedInt as Any)` creates an `Optional<Any>` while that inner `Any` is by itself `Optional<Int>`. Then you pass `Optional<Any>` (hidden `Optional<Optional<Int>>`) to be stored by an `Optional<Optional<Any>`. I'd guess that the compiler just does something like this:

```swift
let _: Any?? = Optional.some(/* our `Optional<Any> (or: Int??)`*/`)

```

If I'm correct this is an optional with three levels.

While in the other weird case we only get an optional with two levels and for some weird reason `type(of:)` can't extract the type of the most wrapped value.

I hope this is somehow understandable. 😃

---

<div class="post-metadata">

**Author:** ![kansaichris](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/kansaichris/32/2703_2.png) [@kansaichris](https://forums.swift.org/u/kansaichris)\
**Post date:** [June 3, 2019, 8:24am UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/11 "2019-06-03T08:24:09Z")

</div>

Well, I'd be lying if I said that I completely understand what's going on now, but this probably isn't the time or the place for a full primer on how type erasure with `Any` works. Still, it's good to know that I'm not the only one who's a bit surprised by the behavior I encountered earlier. :)

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [June 3, 2019, 8:27am UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/12 "2019-06-03T08:27:24Z")

</div>

We can quickly test it.

```swift
fileprivate protocol Wrapper {
  static func baseType(level: inout Int) -> Any.Type
  func baseType(level: inout Int) -> Any.Type
}

extension Optional: Wrapper {
  fileprivate static func baseType(level: inout Int) -> Any.Type {
    level += 1
    switch Wrapped.self {
    case let wrapper as Wrapper.Type:
      return wrapper.baseType(level: &level)
    default:
      return Wrapped.self
    }
  }

  func baseType(level: inout Int) -> Any.Type {
    level += 1
    switch self {
    case .some(let wrapper as Wrapper):
      return wrapper.baseType(level: &level)
    case .some(let wrapped):
      return type(of: wrapped)
    case .none:
      return Optional.baseType(level: &level)
    }
  }
}

let wrappedValue: String? = "Swift"
let test_1: Any?? = wrappedValue
let test_2: Any?? = Optional(wrappedValue as Any)

var level = 0
print(test_1.baseType(level: &level), level) // prints `Any 2`

level = 0
print(test_2.baseType(level: &level), level) // prints `String 3`

```

This verifies my assumption.

* * *

Filed a bug report: [[SR-10823] `type(of:)` cannot extract the type erased with `Any` · Issue #53213 · apple/swift · GitHub](https://bugs.swift.org/browse/SR-10823)

---

<div class="post-metadata">

**Author:** ![kansaichris](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/kansaichris/32/2703_2.png) [@kansaichris](https://forums.swift.org/u/kansaichris)\
**Post date:** [June 3, 2019, 8:36am UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/13 "2019-06-03T08:36:28Z")

</div>

Oh, now I think I see what you mean! `test_2` is declared as `Any??`, but it's _actually_ an `Any???`. For some reason I didn't realize that `Any` could be hiding any number of layers of optionality behind it, but in hindsight I guess that makes sense—`Any` really does mean _anything_, optional or not.

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [June 3, 2019, 8:38am UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/14 "2019-06-03T08:38:58Z")

</div>

Yep `test_2` in reality is `String???`, but is erased as `Any??`, while `test_1` is `String??` erased as `Any??`. However `type(of:)` seems bugged or there is an issue with implicit existentials here, I really don't know.

---

<div class="post-metadata">

**Author:** ![Peter-Schorn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/peter-schorn/32/11183_2.png) [@Peter-Schorn](https://forums.swift.org/u/Peter-Schorn)\
**Post date:** [July 2, 2020, 5:09am UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/15 "2020-07-02T05:09:04Z")

</div>

Well here's a challenge that I still haven't found an answer too:  
How do you unwrap an arbitrarily nested optional to a single-wrapped optional **while preserving the base type**?. All the solutions in [this post](https://forums.swift.org/t/challenge-flattening-nested-optionals/24083) and all the other posts on this topic I've seen either type-erase the result to `Any?` or don't truly support arbitrarily nested optionals.

---

<div class="post-metadata">

**Author:** ![Jens](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jens/32/12903_2.png) [@Jens](https://forums.swift.org/u/Jens)\
**Post date:** [July 2, 2020, 6:59am UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/16 "2020-07-02T06:59:35Z")

</div>

Finding yourself in a situation where you think you need this is a code smell IMO.

Could you specify a signature for the solution?

Something like

```swift
extension Optional {
  func singleWrapped: Optional<SomeUnspecifiableBaseType> { ... }
}

```

?

I mean, if the type of the input (the "arbitrarily nested optional") is unknowable at compile time (a user could have specified it at runtime), then by definition, it is impossible to represent both the input type and the output (`singleWrapped`) type as anything other than `Optional<Any>` or `Any`.

* * *

If you do know what the final `Wrapped` type is, then it might be possible, but that's not how I understood the challenge.

---

<div class="post-metadata">

**Author:** ![Peter-Schorn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/peter-schorn/32/11183_2.png) [@Peter-Schorn](https://forums.swift.org/u/Peter-Schorn)\
**Post date:** [July 2, 2020, 7:07am UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/17 "2020-07-02T07:07:51Z")

</div>

You're probably right that there is no solution to my question. I was hoping it could be solved with generics, but this is probably not something the type system can handle.

---

<div class="post-metadata">

**Author:** ![Jens](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jens/32/12903_2.png) [@Jens](https://forums.swift.org/u/Jens)\
**Post date:** [July 2, 2020, 7:20am UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/18 "2020-07-02T07:20:51Z")

</div>

How would _any_ type system be able to magically guess what type eg a user or some truly random process result in at runtime?

And how would _you_ represent, textually, for the compiler (ie at compile-time), a type that is only knowable at runtime?

This is what type erasing, `Any` etc is for.

---

<div class="post-metadata">

**Author:** ![Peter-Schorn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/peter-schorn/32/11183_2.png) [@Peter-Schorn](https://forums.swift.org/u/Peter-Schorn)\
**Post date:** [July 2, 2020, 7:36am UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/19 "2020-07-02T07:36:58Z")

</div>

Sorry, I should have been more specific: I didn't mean to suggest that the type would be unknownable at compile time. What I had in mind was a function that used generic types in such a way that it could accept any arbitrarily-nested optional type. The type system would still know at compile time exactly how many levels of optionality the type has and what the base type is.

---

<div class="post-metadata">

**Author:** ![Jens](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jens/32/12903_2.png) [@Jens](https://forums.swift.org/u/Jens)\
**Post date:** [July 2, 2020, 8:09am UTC](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096/20 "2020-07-02T08:09:36Z")

</div>

If you can accept an upper limit of say 10 levels of optionality, then I guess you could use something like the following (which is the same as [this](https://forums.swift.org/t/challenge-flattening-nested-optionals/24083/8)):

```swift
postfix operator …?
/// Unwraps 1 to 10 layers of `Optional`ity.
postfix func …?<T>(v: T??????????) -> T? { (v as? T?) ?? nil }

// Demo:
for _ in 0 ..< 3 {
  let a: Int?????? = Bool.random() ? 123 : nil
  let b: Bool? = Bool.random() ? true : nil
  let c: String???????? = Bool.random() ? "Hello" : nil
  let d: Float??? = Bool.random() ? 1.23 : nil
  let ua = a…?
  let ub = b…?
  let uc = c…?
  let ud = d…?
  print("--")
  print(type(of: ua), " | ", ua ?? "nil")
  print(type(of: ub), " | ", ub ?? "nil")
  print(type(of: uc), " | ", uc ?? "nil")
  print(type(of: ud), " | ", ud ?? "nil")
}

```

Not sure if it would be possible to express in some recursive way that would lift the upper limit.

* * *

I maintain that if you feel the need for something like this, then it is an indication of some deeper problem of your design.

[Next page](https://forums.swift.org/t/challenge-finding-base-type-of-nested-optionals/25096.md?page=2)
