Skip to content

[Observation] Switch Observable to be a non-marker protocol #66993

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 9, 2023

Conversation

natecook1000
Copy link
Member

With support for redundant conformance declarations via macros, the Observable protocol can be a non-marker protocol, which provides more flexibility for evolution in the future.

Note: This requires a change that would allow macros to emit redundant conformances. Without that change, this will fail tests that use the @Observable macro on both a class and its subclass (e.g. Entity and its subclasses here).

rdar://111463883

With support for redundant conformance declarations via macros,
the `Observable` protocol can be a non-marker protocol, which
provides more flexibility for evolution in the future.

rdar://111463883
@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

@phausler
Copy link
Contributor

I'm not sure how making it a non-marker (ABI) protocol makes it more flexible in the future. There are no requirements nor could we add them later without default implementations. Any requirement would need to expose the registrar which doing so would leak internal details.

@natecook1000 natecook1000 marked this pull request as ready for review July 6, 2023 20:01
@natecook1000
Copy link
Member Author

@swift-ci Please test

This change switch to implement the new ExtensionMacro protocol,
the requirement for which includes information about whether the
conformance to the Observable protocol has already been added, either
in the declaration or in a superclass to the macro-attributed type.
This allows the @observable macro to be applied to subclasses of
observable types without redundant-conformance errors.
@natecook1000
Copy link
Member Author

@swift-ci Please test

@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

@natecook1000 natecook1000 merged commit 003b335 into swiftlang:main Jul 9, 2023
@natecook1000 natecook1000 deleted the observable_nonmarker branch July 9, 2023 18:09
@phausler
Copy link
Contributor

phausler commented Jul 9, 2023

umm I disagree with the merge here: my objection was not at all addressed. The implementation did not seem to address the subclassing issue, and the justification of the non-marker protocol seemed to be hand-wavy/nebulous.

@stephentyrone
Copy link
Contributor

This was discussed in detail in the Language Steering Group; the most general point is that the idea of needing to "justify a non-marker protocol" is precisely backwards; all protocols should be non-marker protocols unless there is a specific need for them to be marker protocols, and that does not exist in this case. (It was previously necessary to workaround the interaction of macros with protocol conformance and subclassing, as you well know, but we addressed that by fixing how the compiler handles conformances created by macros.)

natecook1000 added a commit to natecook1000/swift that referenced this pull request Jul 10, 2023
…ang#66993)

With support for redundant conformance declarations via macros,
the `Observable` protocol can be a non-marker protocol, which
provides more flexibility for evolution in the future.

rdar://111463883

This change also switches to the new ExtensionMacro protocol,
the requirement for which includes information about whether the
conformance to the Observable protocol has already been added, either
in the declaration or in a superclass to the macro-attributed type.
This allows the @observable macro to be applied to subclasses of
observable types without redundant-conformance errors.
@DmT021
Copy link
Contributor

DmT021 commented Jul 11, 2023

@natecook1000 Why do you need the Observable protocol in the first place? It seems to be unused, as well as the subject: Subject argument in the functions willSet, didSet, withMutation.

natecook1000 added a commit that referenced this pull request Jul 11, 2023
* Make the `@Observable` macro class only (#67033)

* Make ObservationRegistrar Codable/Hashable

These conformances enable automatic Codable synthesis for Observable
types, and smooth the runway for structs being supported by the
Observable macro in the future.

* Limit Observable macro to classes

This removes the ability for the Observable macro to apply to structs,
and adds diagnostic tests for the three disallowed declaration kinds.

* [Observation] Switch `Observable` to be a non-marker protocol (#66993)

With support for redundant conformance declarations via macros,
the `Observable` protocol can be a non-marker protocol, which
provides more flexibility for evolution in the future.

rdar://111463883

This change also switches to the new ExtensionMacro protocol,
the requirement for which includes information about whether the
conformance to the Observable protocol has already been added, either
in the declaration or in a superclass to the macro-attributed type.
This allows the @observable macro to be applied to subclasses of
observable types without redundant-conformance errors.
@natecook1000
Copy link
Member Author

@DmT021 Even though the Observable protocol currently has no implementation requirements, it does include a variety of semantic requirements that are described in the Observation Swift Evolution proposal.

@DmT021
Copy link
Contributor

DmT021 commented Jul 12, 2023

Yes, I understand that this protocol provides semantics. But is it useful? I mean it doesn't help us to build a compile-time or runtime check that the properties of the objects we want to observe are observable. And programmers also do not see the list of conformances for each object when using their properties in the apply function.

@phausler
Copy link
Contributor

yes; it helps to ensure that usage scopes: such as @Bindable or @State work appropriately. But say you had a method that were to use the withObservationTracking - ideally you would want to ensure observable things were passed into that context - having the protocol gives a hint (or perhaps hard requirement) that those things are in-fact observable. Now of course some properties may be ignored (or a type that just adopts the protocol and not use the macro) that is perfectly reasonable. So it is mainly used as a conveyance of intent.

Now it definitely could exist without it - but when the other use cases are considered (specifically integration with other layers, either SwiftUI or developer created libraries) it makes sense to have some sort of identification that the types are actually observable.

This was a short-coming of KVO. There was no way to tell if a type has adopted it or not. This at least lets the developer using the type know that it was considered.

@DmT021
Copy link
Contributor

DmT021 commented Jul 12, 2023

@phausler Ok, thanks a lot for the detailed answer. And what about the subject argument the functions willSet, didSet, withMutation?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants