[Pitch #3] Incremental migration to concurrency checking

Hi all!

Here's the third pitch for supporting incremental migration to concurrency checking. The full document is here. This revision:

  • Provides some more examples of the effects of @predatesConcurrency on type checking,
  • Extends @predatesConcurrency to protocols to subsume SE-0302's special-case behavior for Error and CodingKey,
  • Removes the Objective-C interoperability bits, which we'll split out, and
  • Now has most of an implementation of the attribute under the name @_predatesConcurrency.

Thanks everyone, looking forward to your feedback.

Doug

14 Likes

I’ve read this version of the text in full and find the overall scheme sensible and more or less intuitive.

Two brief comments, one on the feature and one on the writing:

  • The verb predates has two distinct meanings, and although only one of them makes sense here, the other meaning is less than ideal (namely, it is what a predator does). Fortunately, I see no reason why the feature cannot be named exactly as it’s already described in the text in places: @preconcurrency.

  • I understand the distinction between “full” and “strict” checking, but it seems (in terms of clarity of writing) the terms should be swapped. Both modes check concurrency rules fully, but one enforces them more strictly (with errors) than the other (with warnings)—but currently, the latter is considered “strict”! For the greatest clarity, one might even consider calling these two modes “strict full” checking and “relaxed full” checking, respectively, but I don’t think it’s going to be intuitive for readers that “strict” should be less strict than “full.”

7 Likes

Is 'implicitly Sendable' (for nominals, not thinking about tuples yet) from SE-0302 a thing any more? I've lost track of this over the iterations: this pitch seems to be excluding it from its "three Sendable conformance statuses", but then goes on to say:

[...] suppresses the implicit conformance of a struct or enum to Sendable .

...implying there's a fourth Sendable conformance status?

My understanding is that implicitly Sendable and implicitly non-Sendable are two sides of the same coin, in that these checking modes and pre-concurrency flags dictate in what scenarios such types without either explicit conformance or non-conformance are considered to be implicitly Sendable or not.

Two points:

  1. I seem to remember a brief discussion of @predates(feature) instead of a dedicated @predatesConcurrency attribute so that the same feature can be reused across all new language features which may need per API disabling. Is that not a possibility here? (Or perhaps I'm thinking of something different but related.)
  2. Adopting this markup from the latest nightly in a simple project, I was struck by how mindlessly rote it was. Just add Sendable until everything compiles. Do we have any documentation or other resources for users to determine what it means for a type or function to be "safely used in concurrent code", as the Sendable docs put it? Even rereading SE-0302, it's unclear what users would actually have to do to make types Sendable beyond adding the conformance. Am I overthinking this, or is this something to be covered in documentation later?
4 Likes

I think possible confusion between "predates" and "predates" is so unlikely as to be a very silly reason to object to the name. But the fact that preconcurrency is shorter but just as clear is a good objection, so I'm going to back using either that name or the more general @predates(feature) attribute that Jon mentioned.

6 Likes

"Confusion" is not the only reason why we avoid using certain terminology.

I don't agree with any of those reasons, but I'm not in charge.

1 Like

I'd be fine with @preconcurrency; I don't have a strong opinion here, it is shorter, and it does read well as an adjective, e.g., "a preconcurrency function" or "preconcurrency protocol".

I wonder if it even makes sense to call "strict" and "full" different modes at all. We could instead say that there are only two checking modes, "minimal" and "full", and that prior to Swift 6 Sendable-related errors are downgraded to warnings.

Yes, implicitly-synthesized Sendable as described in SE-0302 is still a thing, and provides Sendable conformances for non-public or frozen struct/enum types comprised of other Sendable types. For this proposal, an implicitly-synthesized Sendable conformance is... "Explicitly Sendable", which is definitely confusing. I think we should use a different term here, e.g., "Sendable-conforming" or "known Sendable".

I don't know how well this idea generalizes. For concurrency, we have some special rules around Sendable and global actors, but they only work because there's no ABI impact (by design). I'm having a hard time imagining that there are enough new features where we can provide meaningful "predates" semantics to justify generalizing the syntax now.

We could use more documentation here. In the implementation, I think we would benefit from an educational note specifically on what Sendable conformance means, and to carefully word the diagnostics that help add Sendable conformances / @predatesConcurrency import declarations to avoid leading the user into doing something unsafe. But yes, we'll still need an accessible definition of what Sendable means and when to conform to it correctly.

Doug

5 Likes

Educational notes might be helpful, but given that they're disabled by default and aren't visible in Xcode even when enabled, they won't be very valuable in the short to medium term. In the short term, might be helpful to describe what Sendable means as part of this proposal so users can have at least some bit of definitive documentation?

In addition to documentation, it would also be very useful to fix the thread sanitizer to work properly with the concurrency features so users can test the safety of their types while making them conform to Sendable. Additionally, enhancing the thread sanitizer to detect particular concurrency-specific issues, if any, would also be very useful.

Big +1 to @preconcurrency , it is shorter, more clear and elegant IMO