[Second Review] SE-0364: Warning for Retroactive Conformances of External Types

I don’t quite follow.

If the app is built with statically-linked libraries, and the app conforms one library’s type to another library’s protocol, what does it matter if the upstream library later adds that conformance?

The app will continue to run just fine because it is using the same static library it has always been using. There is no danger here.

When the app developer updates their dependencies and goes to build the app again, they will get a hard error about the conflicting conformance. At that point, they can happily remove their own conformance and new versions of the app will use the library’s conformance.

Again, no danger.

It seems to me that we already have the proper language behavior for this scenario. Am I missing something?

2 Likes

It’s about acknowledging that updating the upstream library might break your target, especially since adding a conformance usually isn’t considered a breaking change. (Not that Swift is perfectly SemVer-friendly, but then nothing is.)

1 Like

Hmm, I don’t quite know how to put this into words, but I have a feeling that “library A doesn’t conform its type to a protocol from library B, but then some future version does” should be quite rare. Maybe vanishingly rare, except for the situation of “Hey, we decided to add a cross-import overlay.”

Conversely, if the protocol and the type both come from the same library… then why wasn’t the conformance always present?


On the other hand, I expect the following scenario should be much more common:

Library A vends a protocol (for example, Numerics vends ElementaryFunctions), with the intention that other people’s types should conform.

Library B vends a type that could conform (for example, a high-precision floating-point number), but does not depend on library A. Maybe the author of B doesn’t even know that A exists, or maybe B just doesn’t use anything from A.

Someone else imports both libraries, and conforms the type to the protocol. This should just work, without any artificial friction.

2 Likes

Library B can be the standard library or some other core library, and the protocol could be something like the next Sendable. Such a scenario wouldn't be "quite rare" but almost inevitable: a version of library A is adopted by an end user who upgrades to a newer version of Swift and provides their own conformances before there's an updated release of library A that has the audited first-party conformances.


Library C imports both libraries A and B, and conforms the type to the protocol. This should just work.
Library D imports both libraries A and B, and conforms the type to the protocol. This should just work.
End user E imports both libraries C and D. The two conformances of the type to the protocol are subtly different. ??? Profit.

1 Like

…and if this proposal gets accepted, then what happens?

All those scenarios turn out exactly the same, with the addition of some extra annotations?

Or some of the libraries end up with reduced functionality because they get dissuaded by the warnings?

I’m just not seeing the upside.

NB: the proposal is already accepted; we are asking for feedback on the revised spelling only.

The rationale for the proposed change in spelling is given above:

It seems I had a similar mis-recollection as Jordan then. I had thought that the proposal only involved resilient libraries. If I had realized it included non-resilient things in statically-linked libraries, I would’ve spoken up during the review.

…and now, looking at the proposal revision history, it seems that it was originally limited to resilient libraries.


Regarding the spelling change then, here is my feedback:

If a resilient type is being retroactively conformed to a resilient protocol, to silence the warning either of the proposed spellings would be fine.

But if either the type or the protocol is not from a resilient library, then the spelling for how to silence the warning should be “no annotation needed”. The warning should always be silenced if something non-resilient is involved.

2 Likes

There is no such thing as an "always silenced warning." It has already been accepted by the language workgroup that there will be a warning—not an error—for retroactive conformances whether resilient libraries are involved or not. Not only was this amply reviewed previously, the change you mention was also made based on feedback during the early review; and not only were you specifically aware of this, you were in fact the first person to review the proposal after the incorporated change was announced.

One line review: to me @retroactive feels like you're giving special powers to the conformance, not that you're doing something fragile. Maybe @fragile would work better?

2 Likes

I think @unsafe would do a very good job of letting the developer adding that annotation that he is marking his code unsafe.

I fear that @retroactive would be obscure to most, and felt like a syntax annoyance imposed by swift for a reason not understood. We would apply the fixit as just a syntax fix without understanding any of the implications.

Whereas @unsafe should at least raise an eyebrow and make any developer think twice before opting in.

Swift uses “unsafe” in a precise, technical way—it’s a description for features that can introduce memory or type safety bugs—and retroactive conformances don’t do that. They’re mistake-prone, but perfectly “safe”.

6 Likes

Could this happen?

  1. A library declares "Date: Identifiable" conformance choosing one type for "id".
  2. Later on Foundation adds its own "Date: Identifiable" choosing a different type for "id".
  3. Before the app rebuilds it exhibits an undefined behaviour which conformance is chosen.
  4. The two types are incompatible enough to cause a crash when one is used instead of another (Double vs Int or Double vs NSNumber).
1 Like

SE-0364 has been accepted.

Thank you to everyone who participated in this review.

Steve Canon
Review Manager

1 Like