When == is called on Feature you would of course expect it to print "Feature" twice. After all, the lhs and rhs are explicitly typed as Feature and it is a final class.
But, if you stick this model into a view via @State like this:
struct ContentView: View {
@State var model = Feature()
var body: some View {
EmptyView()
}
}
It seems really surprising that an explicitly typed value can secretly be some other value under the hood, and so accessing properties or invoking methods will crash.
Just to check, this is specifically a SwiftUI bug and not a compiler bug because SwiftUI is reinterpreting object pointers or similar, is that correct? That is, there is some unsafe code (in C++ or Swift) that sidesteps compiler/runtime protections? Because otherwise something is missing in the compiler.
you've labeled it with some macro or a type / property wrapper, etc
@THING1
class Foo { // or struct / enum
@THING2
var field: Int
}
those added a bunch of hidden stuff that you are not aware of (unless you look deep inside), and then you are introducing your EQ (and, BTW, "hash") that takes into account the fields you know about and ignores the rest. Could this work at all?
No, that’s not how SwiftUI works. Brandon’s class is a regular-old, vanilla final class. The property wrapper is applied to a property on a different type that conforms to SwiftUI’s View protocol.
There’s really no need to further speculate or pick this apart. Brandon’s code is perfectly normal and should work. He’s experiencing a known bug.
…used to compile in Xcode 15 beta 2, but as of beta 3 and later it no longer compiles with the error:
Type 'Feature' does not conform to protocol 'Equatable'
This error seems impossible to fix even though the requirement of Equatable is correctly given.
I also don't really understand how such a compiler error is possible (nor the runtime crash from before) without some kind of soundness problem. How can the presence of the @Observable macro prevent a type from conforming to a protocol? Has this hole been explicitly put into the compiler so that people are not allowed to conform observable objects to Equatable ?
Update: Ok, not as weird as I thought at first, but still a little weird. Defining the Equatable conformance in an extension works: