Skip to content

Commit 49ae51c

Browse files
committed
small cleanups
1 parent 968a64e commit 49ae51c

File tree

2 files changed

+90
-39
lines changed

2 files changed

+90
-39
lines changed

stdlib/public/Distributed/DistributedActor.swift

Lines changed: 80 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,28 @@ import _Concurrency
1515

1616
// ==== Distributed Actor -----------------------------------------------------
1717

18-
19-
2018
/// Common protocol to which all distributed actors conform implicitly.
2119
///
2220
/// The `DistributedActor` protocol generalizes over all distributed actor types.
2321
/// Distributed actor types implicitly conform to this protocol.
2422
///
25-
/// It is not possible to conform to this protocol manually by any other type
26-
/// than a `distributed actor`.
23+
/// It is not possible to conform to this protocol by any other declaration other than a `distributed actor`.
2724
///
2825
/// It is possible to require a type to conform to the
2926
/// ``DistributedActor`` protocol by refining it with another protocol,
3027
/// or by using a generic constraint.
3128
///
29+
/// ## Synthesized properties
30+
/// For every concrete distributed actor declaration, the compiler synthesizes two properties: `actorSystem` and `id`.
31+
/// They witness the ``actorSystem`` and ``id`` protocol requirements of the ``DistributedActor`` protocol.
32+
///
33+
/// It is not possible to implement these properties explicitly in user code.
34+
/// These properties are `nonisolated` and accessible even if the instance is _remote_,
35+
/// because _all_ distributed actor references must store the actor system remote calls
36+
/// will be delivered through, as well as the id identifying the target of those calls.
3237
///
3338
/// ## The ActorSystem associated type
34-
/// Every distributed actor must declare what type of distributed actor system
39+
/// Every distributed actor must declare what type of actor system
3540
/// it is part of by implementing the ``ActorSystem`` associated type requirement.
3641
///
3742
/// This causes a number of other properties of the actor to be inferred:
@@ -98,12 +103,12 @@ import _Concurrency
98103
/// because distributed actors are always managed by a concrete
99104
/// distributed actor system and cannot exist on their own without one.
100105
///
101-
/// It is possible to explicitly declare an parameter-free initializer (`init()`),
106+
/// It is possible to explicitly declare a parameter-free initializer (`init()`),
102107
/// however the `actorSystem` property still must be assigned a concrete actor
103108
/// system instance the actor shall be part of.
104109
///
105110
/// In general it is recommended to always have an `actorSystem` parameter as
106-
/// the last non-defaulted non-closure parameter in every distributed actors
111+
/// the last non-defaulted non-closure parameter in every actor's
107112
/// initializer parameter list. This way it is simple to swap in a "test actor
108113
/// system" instance in unit tests, and avoid relying on global state which could
109114
/// make testing more difficult.
@@ -114,9 +119,10 @@ import _Concurrency
114119
///
115120
/// ### Property: Actor System
116121
/// The ``actorSystem`` property is an important part of every distributed actor's lifecycle management.
117-
/// Both initialization as well as de-initialization require interactions with the actor system,
118-
/// and it is the actor system that delivers
119122
///
123+
/// Both initialization as well as de-initialization require interactions with the actor system,
124+
/// and it is the actor system that handles all remote interactions of an actor, by both sending
125+
/// or receiving remote calls made on the actor.
120126
///
121127
/// The ``actorSystem`` property must be assigned in every designated initializer
122128
/// of a distributed actor explicitly. It is highly recommended to make it a
@@ -130,11 +136,23 @@ import _Concurrency
130136
/// }
131137
/// ```
132138
///
139+
/// Forgetting to initialize the actor system, will result in a compile time error:
140+
///
141+
/// ```swift
142+
/// // BAD
143+
/// init(name: String, actorSystem: Self.ActorSystem) {
144+
/// self.name = name
145+
/// // BAD, will cause compile-time error; the `actorSystem` was not initialized.
146+
/// }
147+
/// ```
148+
///
133149
/// ### Property: Distributed Actor Identity
134150
/// ``id`` is assigned by the actor system during the distributed actor's
135151
/// initialization, and cannot be set or mutated by the actor itself.
136152
///
137-
/// ``id`` is the effective identity of the actor, and is used in equality checks.
153+
/// ``id`` is the effective identity of the actor, and is used in equality checks,
154+
/// as well as the actor's synthesized ``Codable`` conformance if the ``ID`` type
155+
/// conforms to ``Codable``.
138156
///
139157
/// ## Automatic Conformances
140158
///
@@ -153,22 +171,26 @@ import _Concurrency
153171
/// only `nonisolated` `id` and `actorSystem` properties are accessible for their
154172
/// implementations.
155173
///
156-
/// ### Implicit `Codable` conformance
157-
/// If created with an actor system whose `ActorID` is `Codable`, the
174+
/// ### Implicit Codable conformance
175+
/// If created with an actor system whose ``DistributedActorSystem/ActorID`` is ``Codable``, the
158176
/// compiler will synthesize code for the concrete distributed actor to conform
159-
/// to `Codable` as well.
177+
/// to ``Codable`` as well.
160178
///
161179
/// This is necessary to support distributed calls where the `SerializationRequirement`
162-
/// is `Codable` and thus users may want to pass actors as arguments to remote calls.
180+
/// is ``Codable`` and thus users may want to pass actors as arguments to remote calls.
163181
///
164-
/// The synthesized implementations use a single `SingleValueContainer` to
165-
/// encode/decode the `self.id` property of the actor. The `Decoder` required
166-
/// `init(from:)` is implemented by retrieving an actor system from the
167-
/// decoders' `userInfo`, effectively like this:
168-
/// `decoder.userInfo[.actorSystemKey] as? ActorSystem`. The obtained actor
169-
/// system is then used to `resolve(id:using:)` the decoded ID.
182+
/// The synthesized implementations use a single ``SingleValueEncodingContainer`` to
183+
/// encode/decode the ``id`` property of the actor. The ``Decoder`` required
184+
/// ``Decoder/init(from:)`` is implemented by retrieving an actor system from the
185+
/// decoders' `userInfo`, effectively like as follows:
170186
///
171-
/// Use the `CodingUserInfoKey.actorSystemKey` to provide the necessary
187+
/// ```swift
188+
/// decoder.userInfo[.actorSystemKey] as? ActorSystem
189+
// ```
190+
///
191+
/// The such obtained actor system is then used to ``resolve(id:using:)`` the decoded ``ID``.
192+
///
193+
/// Use the ``CodingUserInfoKey/actorSystemKey`` to provide the necessary
172194
/// actor system for the decoding initializer when decoding a distributed actor.
173195
///
174196
/// - SeeAlso: ``DistributedActorSystem``
@@ -192,17 +214,32 @@ public protocol DistributedActor: AnyActor, Identifiable, Hashable
192214
/// to return the same exact resolved actor instance, however all the references would
193215
/// represent logically references to the same distributed actor, e.g. on a different node.
194216
///
195-
/// Conformance to this requirement is synthesized automatically for any
196-
/// `distributed actor` declaration.
217+
/// Depending on the capabilities of the actor system producing the identifiers,
218+
/// the `ID` may also be used to store instance specific metadata.
219+
///
220+
/// ## Synthesized property
221+
///
222+
/// In concrete distributed actor declarations, a witness for this protocol requirement is synthesized by the compiler.
223+
///
224+
/// It is not possible to assign a value to the `id` directly; instead, it is assigned during an actors `init` (or `resolve`),
225+
/// by the managing actor system.
197226
nonisolated override var id: ID { get }
198227

199-
/// The `ActorSystem` that is managing this distributed actor.
228+
/// The ``DistributedActorSystem`` that is managing this distributed actor.
229+
///
230+
/// It is immutable and equal to the system assigned during the distributed actor's local initializer
231+
/// (or to the system passed to the ``resolve(id:using:)`` static function).
200232
///
201-
/// It is immutable and equal to the system passed in the local/resolve
202-
/// initializer.
233+
/// ## Synthesized property
203234
///
204-
/// Conformance to this requirement is synthesized automatically for any
205-
/// `distributed actor` declaration.
235+
/// In concrete distributed actor declarations, a witness for this protocol requirement is synthesized by the compiler.
236+
///
237+
/// It is required to assign an initial value to the `actorSystem` property inside a distributed actor's designated initializer.
238+
/// Semantically, it can be treated as a `let` declaration, that must be assigned in order to fully-initialize the instance.
239+
///
240+
/// If a distributed actor declares no initializer, its default initializer will take the shape of `init(actorSystem:)`,
241+
/// and initialize this property using the passed ``DistributedActorSystem``. If any user-defined initializer exists,
242+
/// the default initializer is not synthesized, and all the user-defined initializers must take care to initialize this property.
206243
nonisolated var actorSystem: ActorSystem { get }
207244

208245
/// Resolves the passed in `id` against the `system`, returning
@@ -215,6 +252,8 @@ public protocol DistributedActor: AnyActor, Identifiable, Hashable
215252
/// the system, allowing it to take over the remote messaging with the
216253
/// remote actor instance.
217254
///
255+
/// - Postcondition: upon successful return, the returned actor's ``id`` and ``actorSystem`` properties
256+
/// will be equal to the values passed as parameters to this method.
218257
/// - Parameter id: identity uniquely identifying a, potentially remote, actor in the system
219258
/// - Parameter system: `system` which should be used to resolve the `identity`, and be associated with the returned actor
220259
static func resolve(id: ID, using system: ActorSystem) throws -> Self
@@ -226,11 +265,15 @@ public protocol DistributedActor: AnyActor, Identifiable, Hashable
226265
extension DistributedActor {
227266

228267
/// A distributed actor's hash and equality is implemented by directly delegating to its ``id``.
268+
///
269+
/// For more details see the "Hashable and Identifiable conformance" section of ``DistributedActor``.
229270
nonisolated public func hash(into hasher: inout Hasher) {
230271
self.id.hash(into: &hasher)
231272
}
232273

233274
/// A distributed actor's hash and equality is implemented by directly delegating to its ``id``.
275+
///
276+
/// For more details see the "Hashable and Identifiable conformance" section of ``DistributedActor``.
234277
nonisolated public static func ==(lhs: Self, rhs: Self) -> Bool {
235278
lhs.id == rhs.id
236279
}
@@ -245,7 +288,7 @@ extension CodingUserInfoKey {
245288
/// conform to ``DistributedActorSystem``.
246289
///
247290
/// Forgetting to set this key will result in that initializer throwing, because
248-
/// an actor system is required.
291+
/// an actor system is required in order to call ``DistributedActor/resolve(id:using:)`` using it.
249292
@available(SwiftStdlib 5.7, *)
250293
public static let actorSystemKey = CodingUserInfoKey(rawValue: "$distributed_actor_system")!
251294
}
@@ -315,9 +358,17 @@ extension DistributedActor {
315358

316359
// ==== isRemote / isLocal -----------------------------------------------------
317360

361+
/// Verifies if the passed ``DistributedActor`` conforming type is a remote reference.
362+
/// Passing a type not conforming to ``DistributedActor`` may result in undefined behavior.
363+
///
364+
/// Official API to perform this task is `whenLocal`.
318365
@_silgen_name("swift_distributed_actor_is_remote")
319366
public func __isRemoteActor(_ actor: AnyObject) -> Bool
320367

368+
/// Verifies if the passed ``DistributedActor`` conforming type is a local reference.
369+
/// Passing a type not conforming to ``DistributedActor`` may result in undefined behavior.
370+
///
371+
/// Official API to perform this task is `whenLocal`.
321372
public func __isLocalActor(_ actor: AnyObject) -> Bool {
322373
return !__isRemoteActor(actor)
323374
}

stdlib/public/Distributed/DistributedActorSystem.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,12 @@ import _Concurrency
5353
///
5454
/// ## Implementing a DistributedActorSystem
5555
///
56-
/// The following section is dedicated to distributed actor system library authors, and generally can be skipped over
56+
/// This section is dedicated to distributed actor system library authors, and generally can be skipped over
5757
/// by library users, as it explains the interactions of synthesized code and specific distributed actor system methods
5858
/// and how they must be implemented.
5959
///
6060
/// Methods discussed in this section are generally not intended to be called directly, but instead will have calls
61-
/// generated to them from distributed actor declarations in appropriate places (such as initializers, `distributed func` calls etc).
61+
/// generated to them from distributed actor declarations in appropriate places (such as initializers, `distributed func` calls, or `distributed` computed properties).
6262
///
6363
/// ### Assigning and Resigning Actor Identifiers
6464
///
@@ -91,7 +91,7 @@ import _Concurrency
9191
/// It can be as small as an integer based identifier, or as large as a series of key-value pairs identifying the actor.
9292
///
9393
/// The actor system must retain a mapping from the ``ActorID`` to the specific actor _instance_ which it is given in
94-
/// ``actorReady(_)`` in order to implement the ``resolve(id:using:)`` method, which is how incoming and outgoing remote calls are made possible.
94+
/// ``actorReady(_:)`` in order to implement the ``resolve(id:using:)`` method, which is how incoming and outgoing remote calls are made possible.
9595
///
9696
/// Users have no control over this assignment, nor are they allowed to set the `id` property explicitly.
9797
/// The ``DistributedActor/id`` is used to implement the distributed actor's ``Hashable``, ``Equatable``,
@@ -150,16 +150,16 @@ import _Concurrency
150150
///
151151
/// ### Resolving (potentially remote) Distributed Actors
152152
///
153-
/// An important functionality of any distributed actor system is being able to turn a ``DistributedActor`` type and ``ActorID``
154-
/// into a reference to such actor, regardless where the actor is located. The ID should have enough information stored
153+
/// An important aspect of any distributed actor system is being able to turn a ``DistributedActor`` type and ``ActorID``
154+
/// into a reference to an actor (instance), regardless where the actor is located. The ID should have enough information stored
155155
/// to be able to make the decision of _where_ the actor is located, without having to contact remote nodes. Specifically,
156156
/// the implementation of ``DistributedActorSystem/resolve(id:as:)`` is _not_ `async` and should _not_ perform long running
157157
/// or blocking operations in order to return.
158158
///
159159
/// > Note: Currently only concrete distributed actors types can be resolved.
160160
///
161161
/// The actor system's ``DistributedActorSystem/resolve(id:as:)`` method is called by the compiler whenever end-users
162-
/// call the ``DistributedActor``'s ``resolve(id:using:)`` method. The return types of those methods differ,
162+
/// call the ``DistributedActor``'s ``DistributedActor/resolve(id:using:)`` method. The return types of those methods differ,
163163
/// as the actor system's return type is `Act?` (and it may throw if unable to resolve the `ActorID`).
164164
///
165165
/// The actor system's `resolve` returning `nil` means that the ``ActorID`` passed to it refers to a _remote_
@@ -171,10 +171,10 @@ import _Concurrency
171171
/// Finally, calls on a _remote_ distributed actor reference's distributed methods are turned into invocations of
172172
/// `remoteCall(on:target:invocation:returning:throwing:)` (or `remoteCallVoid(on:target:invocation:throwing:)` for Void returning methods).
173173
///
174-
/// Implementing the remote calls correctly and efficiently is one of the most important tasks for a distributed actor system library.
175-
/// Since those methods are not currently expressible as protocol requirements in Swift due to their advanced use
176-
/// of generics, and therefore will not appear in the protocol's documentation as explicit requirements, we present
177-
/// their signatures that a conforming type has to implement here:
174+
/// Implementing the remote calls correctly and efficiently is the important task for a distributed actor system library.
175+
/// Since those methods are not currently expressible as protocol requirements due to advanced use of generics
176+
/// combined with type aliases, they will not appear in the protocol's documentation as explicit requirements.
177+
/// Instead, we present their signatures that a conforming type has to implement here:
178178
///
179179
/// > Note: Although the `remoteCall` methods are not expressed as protocol requirements in source,
180180
/// > the compiler will provide the same errors as-if they were declared explicitly in this protocol.

0 commit comments

Comments
 (0)