In SE-0352, implicitly opened existentials when calling generic functions was added to the language. I'm hoping that generic struct initializers can be used as a generic function in this manner. I don't see what would prevent that from working. I'm finding mixed results, and I'm looking for some help to solve a problem.
The problem: I'm using SwiftUI to build a View hierarchy. In the parent view, I have a value of type any InsettableShape
. I'd like to initialize a generic child view which unwraps that existential, so that it can work with some InsettableShape
.
I've simplified the problem to some example code, which doesn't depend on the real SwiftUI, and even removes complexity like protocols with associated type or self requirements from the picture. I'm running into a Type 'any InsettableShape' cannot conform to 'InsettableShape'
error.
// Simplified stubs to produce a minimal test case
protocol View {
var body: Any { get }
}
protocol InsettableShape {
var someMember: Any { get }
}
// Child view, pretty close to the real use case
struct MySymbolView<S: InsettableShape>: View {
private let shape: S
init(shape: S) {
self.shape = shape
}
var body: Any {
return shape
}
}
// Somewhere inside the parent view, just a test
func test(testShape: any InsettableShape) {
let result1 = MySymbolView(shape: testShape)
// error: type 'any InsettableShape' cannot conform to 'InsettableShape'
}
As I've spent time reading the proposal linked above and experimenting with code, I've also found that if I simplify MySymbolView
to only use a generic initializer, and not be a generic struct as a whole, then the compiler is happy. So it seems that initializers can in fact take advantage of SE-0352.
struct MySymbolView: View {
init(shape: some InsettableShape) {
// self.shape = shape
}
var body: Any {
return true
}
}
However, this isn't very useful to me, since I cannot actually build the child view I'm hoping to build without storing the value, and I cannot do that without specifying the type, which needs the generic placeholder outside the initializer.
Questions: Is there a better way to use a value of an existential type and unwrap it to produce a child view? In addition, can someone help me understand what exactly prevents the compiler from unwrapping and initializing successfully in the example above? I couldn't find anything in the proposal that mentioned why this case would be limited if the initializer on its own is fine.
Side note: I know that the iOS17 SDK introduced the AnyShape
type, but I'm targeting a previous version of iOS. If the best solution possible here is to introduce my own AnyShape
struct, I'm honestly not sure where to start on that, and would appreciate any guidance.
Thanks!