@@ -15,23 +15,28 @@ import _Concurrency
15
15
16
16
// ==== Distributed Actor -----------------------------------------------------
17
17
18
-
19
-
20
18
/// Common protocol to which all distributed actors conform implicitly.
21
19
///
22
20
/// The `DistributedActor` protocol generalizes over all distributed actor types.
23
21
/// Distributed actor types implicitly conform to this protocol.
24
22
///
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`.
27
24
///
28
25
/// It is possible to require a type to conform to the
29
26
/// ``DistributedActor`` protocol by refining it with another protocol,
30
27
/// or by using a generic constraint.
31
28
///
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.
32
37
///
33
38
/// ## 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
35
40
/// it is part of by implementing the ``ActorSystem`` associated type requirement.
36
41
///
37
42
/// This causes a number of other properties of the actor to be inferred:
@@ -98,12 +103,12 @@ import _Concurrency
98
103
/// because distributed actors are always managed by a concrete
99
104
/// distributed actor system and cannot exist on their own without one.
100
105
///
101
- /// It is possible to explicitly declare an parameter-free initializer (`init()`),
106
+ /// It is possible to explicitly declare a parameter-free initializer (`init()`),
102
107
/// however the `actorSystem` property still must be assigned a concrete actor
103
108
/// system instance the actor shall be part of.
104
109
///
105
110
/// 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
107
112
/// initializer parameter list. This way it is simple to swap in a "test actor
108
113
/// system" instance in unit tests, and avoid relying on global state which could
109
114
/// make testing more difficult.
@@ -114,9 +119,10 @@ import _Concurrency
114
119
///
115
120
/// ### Property: Actor System
116
121
/// 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
119
122
///
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.
120
126
///
121
127
/// The ``actorSystem`` property must be assigned in every designated initializer
122
128
/// of a distributed actor explicitly. It is highly recommended to make it a
@@ -130,11 +136,23 @@ import _Concurrency
130
136
/// }
131
137
/// ```
132
138
///
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
+ ///
133
149
/// ### Property: Distributed Actor Identity
134
150
/// ``id`` is assigned by the actor system during the distributed actor's
135
151
/// initialization, and cannot be set or mutated by the actor itself.
136
152
///
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``.
138
156
///
139
157
/// ## Automatic Conformances
140
158
///
@@ -153,22 +171,26 @@ import _Concurrency
153
171
/// only `nonisolated` `id` and `actorSystem` properties are accessible for their
154
172
/// implementations.
155
173
///
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
158
176
/// compiler will synthesize code for the concrete distributed actor to conform
159
- /// to `Codable` as well.
177
+ /// to `` Codable` ` as well.
160
178
///
161
179
/// 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.
163
181
///
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:
170
186
///
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
172
194
/// actor system for the decoding initializer when decoding a distributed actor.
173
195
///
174
196
/// - SeeAlso: ``DistributedActorSystem``
@@ -192,17 +214,32 @@ public protocol DistributedActor: AnyActor, Identifiable, Hashable
192
214
/// to return the same exact resolved actor instance, however all the references would
193
215
/// represent logically references to the same distributed actor, e.g. on a different node.
194
216
///
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.
197
226
nonisolated override var id : ID { get }
198
227
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).
200
232
///
201
- /// It is immutable and equal to the system passed in the local/resolve
202
- /// initializer.
233
+ /// ## Synthesized property
203
234
///
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.
206
243
nonisolated var actorSystem : ActorSystem { get }
207
244
208
245
/// Resolves the passed in `id` against the `system`, returning
@@ -215,6 +252,8 @@ public protocol DistributedActor: AnyActor, Identifiable, Hashable
215
252
/// the system, allowing it to take over the remote messaging with the
216
253
/// remote actor instance.
217
254
///
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.
218
257
/// - Parameter id: identity uniquely identifying a, potentially remote, actor in the system
219
258
/// - Parameter system: `system` which should be used to resolve the `identity`, and be associated with the returned actor
220
259
static func resolve( id: ID , using system: ActorSystem ) throws -> Self
@@ -226,11 +265,15 @@ public protocol DistributedActor: AnyActor, Identifiable, Hashable
226
265
extension DistributedActor {
227
266
228
267
/// 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``.
229
270
nonisolated public func hash( into hasher: inout Hasher ) {
230
271
self . id. hash ( into: & hasher)
231
272
}
232
273
233
274
/// 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``.
234
277
nonisolated public static func == ( lhs: Self , rhs: Self ) -> Bool {
235
278
lhs. id == rhs. id
236
279
}
@@ -245,7 +288,7 @@ extension CodingUserInfoKey {
245
288
/// conform to ``DistributedActorSystem``.
246
289
///
247
290
/// 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 .
249
292
@available ( SwiftStdlib 5 . 7 , * )
250
293
public static let actorSystemKey = CodingUserInfoKey ( rawValue: " $distributed_actor_system " ) !
251
294
}
@@ -315,9 +358,17 @@ extension DistributedActor {
315
358
316
359
// ==== isRemote / isLocal -----------------------------------------------------
317
360
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`.
318
365
@_silgen_name ( " swift_distributed_actor_is_remote " )
319
366
public func __isRemoteActor( _ actor : AnyObject ) -> Bool
320
367
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`.
321
372
public func __isLocalActor( _ actor : AnyObject ) -> Bool {
322
373
return !__isRemoteActor( actor )
323
374
}
0 commit comments