I'm not 100% sure I follow here as I couldn't play around with the current state of the project in any way. Are you still going to publish a package to toy around with, even if it's not based on macros yet?
Are you saying that it's not fixable for ObservableObject or is it not fixable for the proposed Observable? If this is going to be a general feature, I don't think we should force its defaults to align with the primary consumer such as SwiftUI. Instead it should provide the necessary tools for the consumer to opt-into the behavior it needs, but generally provide a greater and more common default. While filtering out duplicates is great, it should be opt-in not opt-out as we often want to catch every change, but only on a case by case basis to filter out duplicates (e.g. Void signals should not discard duplicates).
I apologize in advance in case I somehow misunderstood your point here.
I'm beginning to understand the necessity for a second solution, I'm just seeing all this also from the perspective of a newbie to the Swift world. How would I explain there are two different and relatively new observer mechanisms here? It's a bit unfortunate. With common sense (unbiased by expertise) you would expect that Combine will grow to serve also these new demands, that it will go open-source and x-platform, move to the standard library or expand and evolve in whatever way necessary ... I wish it was just named "SwiftUI View Model Observability Kit" haha
No StateObject has a closure that it uses to generate the object once and lazily, on every re-creation of the view there is no new object spawned. State will spawn new value every single time the view is instantiated, throw it away when re-injecting the last value that corresponds the view‘s lifetime. Put a very heavy value into State and you will smash your performance every time that view needs to be instantiated.
In general, very happy to see progress. There have been some great points already brought up so I won't reiterate them. However, I am curious how the ObservedChanges sequence is going to work. Is this going to be a unicast AsyncSequence or a multicast one? Furthermore, is the iterator going to retain the object that gets observed?
ObservedChanges is intended to be unicast. The ObservedChanges and ObservedChanges.Iterator will only hold the Observable weakly. However if we decide to relax the requirements from AnyObject to include structures too that may have to change. Sadly it must have a way to remove the observer in case of cancellation; so we need some sort of back reference.
I'm excited for this direction, it looks very promising for some (non-SwiftUI) problems in a codebase I work on. With Holly's recent update about the need for type wrappers (likely) being obviated by declaration macros, I wondered if you had had any further thoughts about what a macro-based approach for Observable would look like here?
Holly and I have been collaborating on some updates to this for the use of macros. I am in the process of revising the pitch; stay tuned - some of the feedback here and from direct sources has been quite helpful and I think it is turning into something pretty awesome.
Granted observation could be more of a runtime level feature but that would mean that the cost of making something observable would impact the potential complexity and code-generation of non-observable things. I'm not sure (even as powerful as observation is) that meets the bar of what it would mean to be language level. Instead it makes a lot more sense to have the implementation of observation first off be approachable (that folks can tinker on it without needing to build the compiler or runtime libraries from scratch) as well as integratabtle into other use cases more than just observing async sequences of values (e.g. SwiftUI's tracking of values to observe). Macros give us the power of the compiler without needing to go to the extent of inventing new things like obs.
I totally agree with you that making a type able to be observed should be as dead simple as just tossing on some sort of decorator. Hopefully next week I will have the new pitch ready - truth be told it is a pretty extensive document covering all of the nooks and crannies of how things should be observed and what that means so it has taken me a bit to re-write it and explore those bits and the implications for performance and integration. One of the key areas that I think will help is that the new pitch has detailed examples for almost all of the different bits.
I have been a bit under-water with a few tasks - but some of the changes are in a pull request pending on the compiler: [WIP] Initial draft of observation by phausler · Pull Request #63725 · apple/swift · GitHub. It was requested previously to provide some stuff to tinker with and see how it works - right now I am finishing up some of the macro integration (which is still a bit broken in that PR) so it is not fully ready just yet. Here soon @nnnnnnnn and I will be wrangling up a new rendition of the pitch to bring forth some of the changes to the pitch.
The plan of record is to build up the implementation along side the pitch such that it can be used as an experimental module, both for integration into other parts, as well as stand-alone evaluation.
Thank you for the update. I've been lurking in the implementation details since I noticed it and I'm really exiting to see where all this is heading.
I have a few questions that may or may not influence the direction the implementation is following:
Will there be a solution for lazy initialization as needed for SwiftUI?
Will there be a good default for discarding duplicates as an opt-in/out?
Can the macro provide the synthesis for the protocol conformance, so that we don't have @Observable attribute near the protocol conformance : Observable?!
While not particularly related to observation, but some simple values could use some form of a 'binding', which either assigns the value to some property or is a referencing structure similar to SwiftUI's Binding property wrapper.
Will we possibly get some ergonomic solution for this to bind observed values as part of the implementation, or at least as a future direction?
Maybe a property wrapper like macro could do both tricks?!
For those interested; after a ton of work revising things and accounting for a lot of the initial feedback here and from folks directly relaying info, there is a newly minted version of this pitch here.
The pitch shifted a touch more towards transactional based changes (since we feel that is more appropriate for observation) and refined a lot of the naming to more clearly indicate both the utility of specific APIs and fall more in-line with other existing APIs. The SwiftUI part is pretty much unchanged from the initial pitch here. In addition we have some initial versions posted as a pull request which is nearly ready for merging.
We think we are really close to a great solution here and would like to drive it forward with yall's help and feedback.