Opaque type returns

I wrote this code to solve the problem of needing to switch between HStack and VStack in SwiftUI:

struct HorVStack<Content: View>: View {
    let needVertical: Bool
    let content: Content
    
    init(needVertical: Bool, @ViewBuilder content: () -> Content) {
        self.needVertical = needVertical
        self.content = content()
    }

    var body: some View {
        if needVertical {
            return AnyView(VStack { content })
        } else {
            return AnyView(HStack { content })
        }
    }
}

This works fine. What I don't understand is why I have to erase the type, even though each return type conforms to View? I feel like there's an interesting lesson regarding the underlying mechanics that I'm missing. Can anyone fill me in?

It has to be one specific type — with some you just keep your exact choice "secret" (to the compiler), exposing (to the user) nothing but the guarantee that it conforms to the protocol.
I guess the driving motivation is the ability to perform optimization, but that should be explained in the discussion about the proposal.

Another option is return a conditional content rather than erasing the type. This might be more efficient too. You could mark var body as a @ViewBuilder or use a dummy Group wrapper.

It's often confusing when you're in a view builder context or not. I sometimes forget var body is just a regular function. So the if conditional in your example isn't creating a conditional content wrapper.

@ViewBuilder
var body: some View { // _ConditionalContent<VStack<Content>, HStack<Content>>
    if needVertical {
        VStack { content }
    } else {
        HStack { content }
    }
}

Hopefully this helps!

2 Likes

It tried that, also removing the @ViewBuilder attribute from the init. It compiles, but simply fails to render.

This is a thing that you can do with classes, sort of. Eh, no big deal if it's not possible, I'm just wondering what sort of hassle it'd take to make it possible. Nothing anyone ought to lose sleep over.

Terms of Service

Privacy Policy

Cookie Policy