-
Notifications
You must be signed in to change notification settings - Fork 199
Add discussion of global actor isolation inference. [SE-0316] #371
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
base: main
Are you sure you want to change the base?
Conversation
This change adds documentation for isolation inference from class inheritance, overridden methods, and protocol conformances.
heckj
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made some suggestions for reframing the sentences to use active voice to make it clear the compiler is the bit doing the inferring in these scenarios. Structurally, this introduces 3 patterns to look for - the 3rd being a "contextual" - but I wasn't super clear on how that tied into the 2 subheadings beneath.
And I asked a couple questions in the review about the logic and what was possible that didn't seem entirely spelled out to me, but I may be misunderstanding.
jasongregori
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is so helpful, thank you! I have some questions below.
| } | ||
| ``` | ||
|
|
||
| In the above example, `Togglable` and all of its requirements |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first example says “Vehicle and all of its methods and properties are isolated to the main actor”. This one says “all of its requirements”. After reading the next example, I think (?) that all of Switch’s methods and properties are also isolated to the main actor? Is that right? If so I find the first wording very helpful and clearer and I think it would help to use it here as well. If not, perhaps that fact could be made clearer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used the language "methods and properties" when talking about concrete types and "requirements" when talking about protocols. But you're right that I should state that when @MainActor is inferred on Switch, all of its methods and properties become isolated to the main actor too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, yeah I think that’s really helpful because it’s changing more than just the requirements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed in bee33b2:
In the example above, the
Togglableprotocol is marked@MainActorto indicate that all of its requirements are isolated to the main actor. Swift infers main-actor isolation on types that conform toTogglable, so all methods and properties ofSwitchare isolated to the main actor, including theisOnproperty and thetogglemethod.
|
|
||
| extension Switch: Togglable { | ||
| mutating func toggle() { | ||
| isOn.toggle() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this example the function toggle is isolated to the main actor but isOn is not isolated to the main actor, is it? And if that’s the case, isn’t it not allowed to use it here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this example, isOn is nonisolated, which is fine to access from a main actor isolated method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, is that because you can only access the toggle function if your Switch is currently living in the main actor and thus any access to isOn would necessarily be on the main actor as well? I always forget about that. Very cool.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jasongregori Do you think it's worth calling out in the explanation of this code listing that isOn is nonisolated? Or ok to make this conversation thread as resolved?
is the subject performing inference.
|
I also think there's a meta discussion about whether inference rules belong in the Language Guide. I think we are long over due for a section in the Language Reference on concurrency, and we'll need that regardless of whether we want this change in the guide. I am happy to start working on a concurrency and data-race safety chapter for the Language Reference! If you have thoughts on this, I'd love to hear them: https://forums.swift.org/t/rfc-documentation-for-isolation-inference-from-classes-and-protocols-se-0316/80343/3 |
|
|
||
| extension Switch: Togglable { | ||
| mutating func toggle() { | ||
| isOn.toggle() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, is that because you can only access the toggle function if your Switch is currently living in the main actor and thus any access to isOn would necessarily be on the main actor as well? I always forget about that. Very cool.
heckj
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One sentence felt really odd to read, so I made a suggestion, but otherwise the changes for active voice were super useful to me. Thank you!
- Adjusted the framing of the examples to be specifically about main-actor isolation, since they use @mainactor, as a concrete example of the global-actor isolation rules. - Removed the headings for classes and protocols -- both of them can be explained in one section together. Although level 4 headings are supported by the tools, using them should be rare. - Added announceDeparture() so the code shows an example of each listed inference rule. - Marked a few places to discuss/fill in with XXX.
colleenish
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First pass edits. Please let me know if you have any questions.
| class Vehicle { | ||
| var currentSpeed = 0.0 | ||
| func makeNoise() { | ||
| // do nothing - an arbitrary vehicle doesn't necessarily make a noise |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // do nothing - an arbitrary vehicle doesn't necessarily make a noise | |
| // Do nothing: an arbitrary vehicle doesn't necessarily make a noise. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this comment mean? "An arbitrary vehicle doesn't necessary make a noise"? What makes it "arbitrary"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed
The Vehicle class is a sort of abstract or placeholder superclass — it doesn't implement much behavior, but its subclasses like Train do. In real Swift code, abstract base classes like this are somewhat rare (unlike some other languages) because protocols or generics are often better tools. However, it does make a pretty approachable teaching example.
For additional context, this code listing follows the running code listing example from the Inheritance chapter earlier in the book. So we might also want to cross-apply edits there.
Also, if there's an editorial preference for colons rather than dashes, I can spin up a tracking bug for that. (Thinking of this because I have a related fix to normalize "OK" vs "Ok" in comments, per Apple Style, on a different branch that includes similar punctuation.)
| [`MainActor`]: https://developer.apple.com/documentation/swift/mainactor | ||
|
|
||
| You can define your own singleton global actors | ||
| using the `@globalActor` attribute, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The paragraph under "Global Actors" needs some work:
Global Actors
"The main actor is a global singleton instance of the [MainActor][] type.
Normally, an actor can have multiple instances,
each of which provide independent isolation.
The possibility of multiple instances is why you declare all of an actor's isolated data
as instance properties of that actor.
However, because MainActor is singleton ---
there is only ever a single instance of this type ---
the type alone is sufficient to identify the actor,
allowing you to mark main-actor isolation using just an attribute.
This approach gives you more flexibility to organize your code
in the way that works best for you."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed. Did you want to revisit this paragraph more together, or does the edit above fix the issues?
| ``` | ||
|
|
||
| In the example above, | ||
| the `Vehicle` class is isolated to the main actor --- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| the `Vehicle` class is isolated to the main actor --- | |
| the `Vehicle` class isolates to the main actor --- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's discuss wording here.
|
|
||
| @MainActor | ||
| func makeNoise() { | ||
| // do nothing - an arbitrary vehicle doesn't necessarily make a noise |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // do nothing - an arbitrary vehicle doesn't necessarily make a noise | |
| // Do nothing: an arbitrary vehicle doesn't necessarily make a noise. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, I'm not clear what this comment means.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed
| so all methods and properties of `Switch` are isolated to the main actor, | ||
| including the `isOn` property and the `toggle` method. | ||
|
|
||
| Swift infers isolation from protocols |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| Swift infers isolation from protocols | |
| Swift only infers isolation from protocols |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed.
My original placement of "only" is right next to the word that it modifies, to avoid ambiguity — do you think there's any risk of a reader misreading this? For example, to misread as "Swift infers isolation" but it doesn't do anything else. The original was based on editorial guidance I've gotten in the past, moving the "only" to the most specific location.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revert to "only when...". Sounds good to me!
| including the `isOn` property and the `toggle` method. | ||
|
|
||
| Swift infers isolation from protocols | ||
| only when you write the conformance as part of the type's declaration. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| only when you write the conformance as part of the type's declaration. | |
| when you write the conformance as part of the type's declaration. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed
| Swift infers isolation from protocols | ||
| only when you write the conformance as part of the type's declaration. | ||
| If you write the conformance in an extension, | ||
| then isolation inference applies to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| then isolation inference applies to | |
| then isolation inference only applies to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed. Same reason for my original wording as above — although I think the risk of misreading is much lower here.
| only when you write the conformance as part of the type's declaration. | ||
| If you write the conformance in an extension, | ||
| then isolation inference applies to | ||
| only requirements that are part of that the extension. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| only requirements that are part of that the extension. | |
| requirements that are part of that extension. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed
Co-authored-by: Colleen Toporek <colleen_toporek@apple.com>
Both the previous commit and a commit already on 'main' added a missing word in the Global Actors section.
This change adds documentation for isolation inference from class inheritance, overridden methods, and protocol conformances.
These rules are buried in old proposal documents, and they deserve documentation in TSPL, especially because they can be difficult to reason about. These rules were originally added in SE-0316.
This does not cover all cases of actor isolation inference; the rules for isolation inference of closures needs to be covered, but I think that belongs in the
Sendablesection because it's based on whether or not a closure type can be called from outside the current concurrency context.I started an RFC thread on the forums about this change here: https://forums.swift.org/t/rfc-documentation-for-isolation-inference-from-classes-and-protocols-se-0316/80343.
Fixes: rdar://160642164