So e.g. you can’t use `some`-typed variables or stored properties.
A `some`-typed variable or stored property wouldn't make any sense because it would be a variable that has a concrete but unknown type. You can't assign something to such a variable, because there's no way to know whether the value you're trying to assign matches the hidden concrete type of the variable.
Perhaps the "automatic type-erasure" feature you're wanting is actually generalized existentials ([1])? Generalized existentials would allow you to declare a variable whose type can be "any Equatable", rather than "some (specific but unknown) Equatable", and the compiler would allow you to "open" the existential and use it like a generic type (without throwing the "protocol can only be used as a generic constraint because it has Self or associatedtype requirements" error).
[0]: https://docs.swift.org/swift-book/LanguageGuide/OpaqueTypes.... [1]: https://github.com/apple/swift/blob/master/docs/GenericsMani...
let strings: some Collection = ["hello", "world"]
[0]https://github.com/apple/swift-evolution/blob/master/proposa...A simple example: [0]. There are workarounds for this specific issue, but trying to do complex stuff sometimes surfaces inscrutable limitations that I can't quite figure out. And with no documentation relevant to a particular case, no Google hits, not even on Apple's forums, and the uncertainty of error messages, I'm not even sure if I'm doing something wrong or it just can't/shouldn't be done. I have to try random things until it works...until it doesn't.
I'm currently experimenting with a SwiftUI layer for a game engine [1], and running into weird undocumented differences between macOS and iOS (like view backgrounds clipping at stack container edges on macOS but not on iOS) that I can't be sure if they're bugs or what. Still, I love SwiftUI.
Also see EmptyView [2]
[0] https://gist.github.com/ShinryakuTako/5a7b32bbf4f4c3874439c2...
[1] https://github.com/InvadingOctopus/octopuskit
[2] https://forums.swift.org/t/how-do-views-like-emptyview-confo...
class ViewContainer<ViewType: View> {
var view: ViewType
init(view: ViewType) {
self.view = view
}
}
extension ViewContainer where ViewType == EmptyView {
convenience init() {
self.init(view: EmptyView())
}
}
With this code, writing `ViewContainer()` will produce a `ViewContainer<EmptyView>`. Writing `ViewContainer<Text>()` will fail with an error (as expected).Note that since this is statically-typed, the following will fail:
let container = ViewContainer()
container.view = Text("wat")
If you want to be able to do that, you'd have to write something like let container = ViewContainer(view: AnyView(EmptyView()))
container.view = AnyView(Text("wat"))But I do need to be able to change the view during runtime, so I settled on just type-erasing to AnyView for now.
Your workaround is to use the AnyView type I guess. Or a conditional with either EmptyView or the template type (displayed).
What would be the name of the feature that allows you to use a default template type if no argument is given to figure out the type to use?
Yes, I made the init generic instead of the type, and made the property an AnyView, but I've read that AnyView may decrease performance (probably because of reasons discussed in this post's article.)
var viewContainer2 = ViewContainer<EmptyView>()
But that's probably not what you want is it. Default generic arguments aren't implemented yet, see (https://stackoverflow.com/questions/42015081/can-i-assign-a-...). It would have possibly removed the <EmptyView> aspect. So you always have to give a type to ViewContainer, if you provide no way for the compiler to infer it.Yes, that would be a workaround for myself, but for a game engine's API, it'd be ugly to require users to write that every time. :)
And there are cases where they might not even know the type.
And it seems I didn't understand your problem, you wanting a variable that can change it's type instead of just some syntactic sugar, hmm.
Or it might be something else.
But how do things like EmptyView work? How do they conform to the View protocol without having a body property (that must also be a View)?
[0]: https://developer.apple.com/documentation/swiftui/emptyview/... [1]: https://developer.apple.com/documentation/swiftui/view/32785...
public struct EmptyView: View {
@inlinable public init()
public typealias Body = Never
}
Because Body is Never, you can't access EmptyView's body property.https://forums.swift.org/t/how-do-views-like-emptyview-confo...
> Thread 1: Fatal error: body() should not be called on EmptyView.
So I don't think the implementation is doing anything beyond the fatalError() call from that forum thread. At least not at this point in time.