Cannot use `nil` or `.none` with Optional<some T>

struct Wot: View {
    let model: String?

    var body: Optional<some View> {
        guard let model else {
            return nil
        }

        return Text(model)
    }
}

:x: Underlying type for opaque result type 'Optional' could not be inferred from return expression

Using .none instead of nil simply changes it to:

:x: Type of expression is ambiguous without a type annotation

The code as written seems like it should work, in principle. While I understand literally what the compiler errors say, I don't understand why it thinks it needs me to spell the type information out for it. It's clear what the opaque return type is from the non-nil return.

Is this something that may be fixed in future?

Is there a workaround, in the interim?

[Assume that it's impossible to specify the opaque type even if I wanted to, because in the real world cases where I'm hitting this, that type isn't available to me as it's pre-opaqued by SwiftUI view modifiers, or is a horrendously complicated type that's practically impossible to deduce¹.]


¹ Tangentially, I so very much wish Swift had a ? (or whatever) type placeholder like some languages, whereby the compiler / IDE just figures it out for me and amends the code.

1 Like

I guess View in your example is SwiftUI.View? It has associatedtype Body which you can use to refer to body's return type.

struct Wot: View {
  let model: String?

  var body: Optional<some View> {
    guard let model else {
      return Body.none
    }

    return Text(model)
  }
}
6 Likes

Oh wow, that's so much easier than I feared. Thanks!

(I still think this extra ceremony shouldn't be necessary, but Body.none instead of nil isn't too big a deal)

1 Like

Now that begs the question why

struct Wot: View {
  let model: String?

  var body: Optional<some View> {
    guard let model else {
      return Body.none
    }

    return Text(model)
  }
}

can't be replaced with

struct Wot: View {
  let model: String?

  // error: 'some' types are only permitted in properties, subscripts, and functions
  typealias Body = (some View)?

  var body: Body {
    guard let model else {
      return Body.none
    }

    return Text(model)
  }
}

because TIL opaque types can be used to satisfy associatedtype requirements, but only implicitly?

Opaque types are not proper types in-and-of themselves. They must, at the point of declaration, have some underlying type that the compiler is able to determine. When detached from a declaration which can provide that type, as in typealias Body = (some View)?, the compiler (today) has no way to determine what the underlying type should be. (We don't attempt to 'link' the opaque type to body across the typealias.)

5 Likes

What is the purpose of this type? Can you share its View conformance code?

What do you mean?

Sorry, my bad, I didn't know that Optional already conforms to SwiftUI.View, that's why I was asking you to share the protocol conformance code. :sob:

But I am still curious about the purpose of Optional<some View>.

What is the difference between Optional<some View> and _ConditionalContent<Text, EmptyView> when I can define Wot in 2 different ways like these:

struct Wot: View {
  let model: String?

  var body: Optional<some SwiftUI.View> {    // Optional<Text>
    guard let model else {
      return Body.none
    }

    return Text(model)
  }
}

struct Wot: View {
  let model: String?

  var body: some View {    // _ConditionalContent<Text, EmptyView>
    if let model { Text(model) } else { EmptyView() }
  }
}
2 Likes

I wrote a little about that as part of Hiding SwiftUI views. Result builders have a lot of limitations (and some annoyances), so it's often nice to disable them. That you can do this with SwiftUI is often overlooked (I myself didn't consciously realise I was in fact doing this until just recently!).

6 Likes