I’m building an app in Embedded Swift and I’m trying to implement a navigation controller that handles a stack of views. It looks something like this:
struct NavigationController {
private var views: [any View] = []
func push(_ view: any View) {
views.append(view)
}
func draw() {
for view in views {
view.draw()
}
}
}
Where it contains an array of structs conforming to View and functions to operate on them. The View protocol introduces requirements that the NavigationController needs to operate on them, like:
protocol View {
mutating func draw()
}
I understand why using existentials this way isn’t allowed, but I’m having trouble coming up with a way to implement this that doesn’t require their use.
Some things that might help/hurt:
Which views will be pushed to the stack can only be known at runtime, since it depends on user input.
All of the types (structs) that conform to View are known at compile time, because the library is not shared.
Views have stored properties that control their state, animations, etc.
What strategies might work to avoid using existentials in this situation?
You can make a wrapper View enum with cases for each possible conformer. You can then implement the View interface to manually to dispatch each cases' method.
Alternatively you could make protocol View: AnyObject.
I can’t find the discussion right now, but is the rationale for the current restriction to avoid the runtime overhead of witness tables and dynamic dispatch on structs in Embedded?
I get the idea of intentionally not supporting things like that in certain contexts, but that reasoning seems to fall apart when the common workaround (in this case, enums as you described in your previous reply) feels essentially like self-implemented dynamic dispatch.
I think the difference is, that with the enum approach all cases are statically known. If you use any this is not the case because the conformer could come from an unknown consumer of your module.
A future direction might be to annotate protocols in a way that they are "sealed", so that only you can conform to them in your module.