Skip to content

Commit 2418aeb

Browse files
committed
[Distributed] documentation
1 parent e8edebc commit 2418aeb

File tree

2 files changed

+156
-9
lines changed

2 files changed

+156
-9
lines changed

stdlib/public/Distributed/DistributedActor.swift

Lines changed: 150 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,151 @@ import _Concurrency
1515

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

18+
19+
1820
/// Common protocol to which all distributed actors conform implicitly.
1921
///
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+
/// ```
2387
///
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.
2690
///
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
28157
/// If created with an actor system whose `ActorID` is `Codable`, the
29158
/// 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.
33163
///
34164
/// The synthesized implementations use a single `SingleValueContainer` to
35165
/// encode/decode the `self.id` property of the actor. The `Decoder` required
@@ -40,6 +170,10 @@ import _Concurrency
40170
///
41171
/// Use the `CodingUserInfoKey.actorSystemKey` to provide the necessary
42172
/// actor system for the decoding initializer when decoding a distributed actor.
173+
///
174+
/// - SeeAlso: ``DistributedActorSystem``
175+
/// - SeeAlso: ``Actor``
176+
/// - SeeAlso: ``AnyActor``
43177
@available(SwiftStdlib 5.7, *)
44178
public protocol DistributedActor: AnyActor, Identifiable, Hashable
45179
where ID == ActorSystem.ActorID,
@@ -102,6 +236,13 @@ extension DistributedActor {
102236
// ==== Codable conformance ----------------------------------------------------
103237

104238
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
105246
@available(SwiftStdlib 5.7, *)
106247
public static let actorSystemKey = CodingUserInfoKey(rawValue: "$distributed_actor_system")!
107248
}

stdlib/public/Distributed/DistributedActorSystem.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,12 @@ public struct ExecuteDistributedTargetError: DistributedActorSystemError {
581581
}
582582
}
583583

584+
/// Error thrown by distributed actor systems while encountering encoding/decoding
585+
/// issues.
586+
///
587+
/// Also thrown when attempt to decode ``DistributedActor`` is made,
588+
/// but no ``DistributedActorSystem`` is available in the `Decoder`'s
589+
/// `userInfo[.actorSystemKey]`, as it is required to perform the resolve call.
584590
@available(SwiftStdlib 5.7, *)
585591
public struct DistributedActorCodingError: DistributedActorSystemError {
586592
public let message: String

0 commit comments

Comments
 (0)