@@ -15,21 +15,151 @@ import _Concurrency
15
15
16
16
// ==== Distributed Actor -----------------------------------------------------
17
17
18
+
19
+
18
20
/// Common protocol to which all distributed actors conform implicitly.
19
21
///
20
- /// It is not possible to conform to this protocol manually explicitly.
21
- /// Only a 'distributed actor' declaration or protocol with 'DistributedActor'
22
- /// requirement may conform to this protocol.
22
+ /// The `DistributedActor` protocol generalizes over all distributed actor types.
23
+ /// Distributed actor types implicitly conform to this protocol.
24
+ ///
25
+ /// It is not possible to conform to this protocol manually by any other type
26
+ /// than a `distributed actor`.
27
+ ///
28
+ /// It is possible to require a type conform to the
29
+ /// ``DistributedActor`` protocol by refining it with another protocol,
30
+ /// or by using a generic constraint.
31
+ ///
32
+ ///
33
+ /// ## The ActorSystem associated type
34
+ /// Every distributed actor must declare what type of distributed actor system
35
+ /// it is part of by implementing the ``ActorSystem`` associated type requirement.
36
+ ///
37
+ /// This causes a number of other properties of the actor to be inferred:
38
+ /// - the ``SerializationRequirement`` that will be used at compile time to
39
+ /// verify `distributed` target declarations are well formed,
40
+ /// - if the distributed actor is `Codable`, based on the ``ID`` being Codable or not,
41
+ /// - the type of the `ActorSystem` accepted in the synthesized default initializer.
42
+ ///
43
+ /// A distributed actor must declare what type of actor system it is ready to
44
+ /// work with by fulfilling the ``ActorSystem`` type member requirement:
45
+ ///
46
+ /// ```swift
47
+ /// distributed actor Greeter {
48
+ /// typealias ActorSystem = GreetingSystem // which conforms to DistributedActorSystem
49
+ ///
50
+ /// func greet() -> String { "Hello!" }
51
+ /// }
52
+ /// ```
53
+ ///
54
+ /// ### The DefaultDistributedActorSystem type alias
55
+ /// Since it is fairly common to only be using one specific type of actor system
56
+ /// within a module or entire codebase, it is possible to declare the default type
57
+ /// or actor system all distributed actors will be using in a module by declaring
58
+ /// a `DefaultDistributedActorSystem` module wide typealias:
59
+ ///
60
+ /// ```swift
61
+ /// import Distributed
62
+ /// import AmazingActorSystemLibrary
63
+ ///
64
+ /// typealias DefaultDistributedActorSystem = AmazingActorSystem
65
+ ///
66
+ /// distributed actor Greeter {} // ActorSystem == AmazingActorSystem
67
+ /// ```
68
+ ///
69
+ /// This declaration makes all `distributed actor` declarations,
70
+ /// which do not explicitly specify an ``ActorSystem`` typealias, to assume the
71
+ /// `AmazingActorSystem` as their `ActorSystem`.
72
+ ///
73
+ /// It is possible for a specific actor to override the system it is using,
74
+ /// by declaring an ``ActorSystem`` type alias as usual:
75
+ ///
76
+ /// ```swift
77
+ /// typealias DefaultDistributedActorSystem = AmazingActorSystem
78
+ ///
79
+ /// distributed actor Amazing {
80
+ /// // ActorSystem == AmazingActorSystem
81
+ /// }
82
+ ///
83
+ /// distributed actor Superb {
84
+ /// typealias ActorSystem = SuperbActorSystem
85
+ /// }
86
+ /// ```
23
87
///
24
- /// The 'DistributedActor' protocol provides the core functionality of any
25
- /// distributed actor .
88
+ /// In general the `DefaultDistributedActorSystem` should not be declared public,
89
+ /// as picking the default should be left up to each specific module of a project .
26
90
///
27
- /// ## Implicit `Codable` conformance
91
+ /// ## Default initializer
92
+ /// While classes and actors receive a synthesized *argument-free default
93
+ /// initializer* (`init()`), distributed actors synthesize a default initializer
94
+ /// that accepts a distributed actor system the actor is part of: `init(actorSystem:)`.
95
+ ///
96
+ /// The accepted actor system must be of the `Self.ActorSystem` type, which
97
+ /// must conform to the ``DistributedActorSystem`` protocol. This is required
98
+ /// because of how distributed actors are always managed by, a concrete
99
+ /// distributed actor system, and cannot exist on their own without one.
100
+ ///
101
+ /// It is possible to explicitly declare an parameter-free initializer (`init()`),
102
+ /// however the `actorSystem` property still must be assigned a concrete actor
103
+ /// system instance the actor shall be part of.
104
+
105
+ /// In general it is recommended to always have an `actorSystem` parameter as
106
+ /// the last non-defaulted non-closure parameter in every distributed actors
107
+ /// initializer parameter list. This way it is simple to swap in a "test actor
108
+ // system" instance in unit tests, and avoid relying on global state which could
109
+ /// make testing more difficult.
110
+ ///
111
+ /// ## Implicit properties
112
+ /// Every concrete `distributed actor` type receives two synthesized properties,
113
+ /// which implement the protocol requirements of this protocol: `id` and `actorSystem`.
114
+ ///
115
+ /// ### Property: Actor System
116
+ /// The ``actorSystem`` property is an important part of every distributed actor's lifecycle management.
117
+ /// Initialization as well as de-initialization both require interactions with the actor system,
118
+ /// and it is the actor system that delivers
119
+ ///
120
+ ///
121
+ /// The ``actorSystem`` property must be assigned in every designated initializer
122
+ /// of a distributed actor explicitly. It is highly recommended to make it a
123
+ /// parameter of every distributed actor initializer, and simply forward the
124
+ /// value to the stored property, like this:
125
+ ///
126
+ /// ```swift
127
+ /// init(name: String, actorSystem: Self.ActorSystem) {
128
+ /// self.name = name
129
+ /// self.actorSystem = actorSystem
130
+ /// }
131
+ /// ```
132
+ ///
133
+ /// ### Property: Distributed Actor Identity
134
+ /// The ``id`` is assigned by the actor system during the distributed actor's
135
+ /// initialization, and cannot be set or mutated by the actor itself.
136
+ ///
137
+ /// The ``id`` is the effective identity of the actor, and is used in equality checks.
138
+ ///
139
+ /// ## Automatic Conformances
140
+ ///
141
+ /// ### Hashable and Identifiable conformance
142
+ /// Every distributed actor conforms to the Hashable and Identifiable protocols.
143
+ /// Its identity is strictly driven by its `id`, and therefore hash and equality
144
+ /// implementations directly delegate to the `id` property.
145
+ ///
146
+ /// Comparing a local distributed actor instance and a remote reference to it
147
+ /// (both using the same ``id``) always returns true, as they both conceptually
148
+ /// point at the same distributed actor.
149
+ ///
150
+ /// It is not possible to implement those protocols relying on the actual actor's
151
+ /// state, because it may be remote and the state may not be available. In other
152
+ /// words, since these protocols must be implemented using `nonisolated` functions,
153
+ /// only `nonisolated` `id` and `actorSystem` properties are accessible for their
154
+ /// implementations.
155
+ ///
156
+ /// ### Implicit `Codable` conformance
28
157
/// If created with an actor system whose `ActorID` is `Codable`, the
29
158
/// compiler will synthesize code for the concrete distributed actor to conform
30
- /// to `Codable` as well. This is necessary to support distributed calls where
31
- /// the `SerializationRequirement` is `Codable` and thus users may want to pass
32
- /// actors as arguments to remote calls.
159
+ /// to `Codable` as well.
160
+ ///
161
+ /// 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.
33
163
///
34
164
/// The synthesized implementations use a single `SingleValueContainer` to
35
165
/// encode/decode the `self.id` property of the actor. The `Decoder` required
@@ -40,6 +170,10 @@ import _Concurrency
40
170
///
41
171
/// Use the `CodingUserInfoKey.actorSystemKey` to provide the necessary
42
172
/// actor system for the decoding initializer when decoding a distributed actor.
173
+ ///
174
+ /// - SeeAlso: ``DistributedActorSystem``
175
+ /// - SeeAlso: ``Actor``
176
+ /// - SeeAlso: ``AnyActor``
43
177
@available ( SwiftStdlib 5 . 7 , * )
44
178
public protocol DistributedActor : AnyActor , Identifiable , Hashable
45
179
where ID == ActorSystem . ActorID ,
@@ -102,6 +236,13 @@ extension DistributedActor {
102
236
// ==== Codable conformance ----------------------------------------------------
103
237
104
238
extension CodingUserInfoKey {
239
+
240
+ /// Key which is required to be set on a `Decoder`'s `userInfo` while attempting
241
+ /// to `init(from:)` a `DistributedActor`. The stored value under this key must
242
+ /// conform to ``DistributedActorSystem``.
243
+ ///
244
+ /// Missing to set this key will result in that initializer throwing, because
245
+ /// an actor system is required
105
246
@available ( SwiftStdlib 5 . 7 , * )
106
247
public static let actorSystemKey = CodingUserInfoKey ( rawValue: " $distributed_actor_system " ) !
107
248
}
0 commit comments