But looking at Apple’s most modern sample code leads us to believe that structs are no longer appropriate for such foundational, currency domain types. If we want granular observation for these types and their nestings, then we should convert them to classes and apply the @Observable
macro.
So, this is a pretty big shift in how we are to build SwiftUI applications, and it seems to have kind of flown under the radar. I think we are all so blown away by the power of the @Observable
macro that we didn’t pay attention to the fact that we are now spreading reference types all over our applications.
And it turns out that the @Observable
macro simply does not work on structs. If you try to apply it to a struct you will instantly be greeted with a compiler error letting you know that the macro currently only works with classes.
But it wasn’t always this way. In the first few betas of Xcode 15 and Swift 5.9 the macro was allowed to be used on structs. However, there were some quirks with it. The most obvious is that at that time in the early betas the ObservationRegistrar
type was not Equatable
or Hashable
, which meant that you would lose automatic synthesis of those conformances on your structs if you use the macro, and that is something that we should expect to keep working.
This motivated us to open up a discussion on the Swift forums on how the @Observable
macro is supposed to work with structs, and boy did that open a can of worms. It turns out that observable structs are a lot more subtle than first meets the eye, and ultimately the core Swift team decided to restrict the macro only to classes for the time being, while confessing that eventually they would like it to work with structs.
So, we want to spend some time investigating what observable structs would mean if they were possible, why they can be tricky, and what one could do to remedy the situation. This discussion will be a little theoretical since the core team made the decision to not support observable structs, but we will use these ideas when we bring the tools from the Observation framework to the Composable Architecture, since one of the main perks of that library is that you get to build your applications with value types instead of reference types.