This is an automated email from the ASF dual-hosted git repository.

hepin pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-pekko.git


The following commit(s) were added to refs/heads/main by this push:
     new 0a09ccc71e Add section on using scala3 union types (#695)
0a09ccc71e is described below

commit 0a09ccc71e28efac5250d448d2e65698b83f508c
Author: Eric Loots <[email protected]>
AuthorDate: Wed Oct 11 13:19:27 2023 +0200

    Add section on using scala3 union types (#695)
    
    * Add section on using scala3 union types
    
    * Code formatting
    
    * Integrate PR feedback
    
    - Point out that Union types are Scala 3 specific
---
 .../pekko/typed/InteractionPatterns3Spec.scala     |  10 ++---
 .../typed/handling-actor-responses-with-scala3.md  |  44 +++++++++++++++++++++
 .../typed/images/adapted-response-scala-3.png      | Bin 0 -> 53066 bytes
 docs/src/main/paradox/typed/index.md               |   1 +
 .../src/main/paradox/typed/interaction-patterns.md |  11 +++++-
 5 files changed, 59 insertions(+), 7 deletions(-)

diff --git 
a/actor-typed-tests/src/test/scala-3/docs/org/apache/pekko/typed/InteractionPatterns3Spec.scala
 
b/actor-typed-tests/src/test/scala-3/docs/org/apache/pekko/typed/InteractionPatterns3Spec.scala
index 26257fe287..404b955208 100644
--- 
a/actor-typed-tests/src/test/scala-3/docs/org/apache/pekko/typed/InteractionPatterns3Spec.scala
+++ 
b/actor-typed-tests/src/test/scala-3/docs/org/apache/pekko/typed/InteractionPatterns3Spec.scala
@@ -138,19 +138,19 @@ class InteractionPatterns3Spec extends 
ScalaTestWithActorTestKit with AnyWordSpe
         sealed trait Command
         final case class Translate(site: URI, replyTo: ActorRef[URI]) extends 
Command
 
-        private type CommandAndResponse = Command | Backend.Response
+        private type CommandAndResponse = Command | Backend.Response // (1)
 
-        def apply(backend: ActorRef[Backend.Request]): Behavior[Command] =
+        def apply(backend: ActorRef[Backend.Request]): Behavior[Command] = // 
(2)
           Behaviors.setup[CommandAndResponse] { context =>
 
             def active(inProgress: Map[Int, ActorRef[URI]], count: Int): 
Behavior[CommandAndResponse] = {
               Behaviors.receiveMessage[CommandAndResponse] {
                 case Translate(site, replyTo) =>
                   val taskId = count + 1
-                  backend ! Backend.StartTranslationJob(taskId, site, 
context.self)
+                  backend ! Backend.StartTranslationJob(taskId, site, 
context.self) // (3)
                   active(inProgress.updated(taskId, replyTo), taskId)
 
-                case Backend.JobStarted(taskId) =>
+                case Backend.JobStarted(taskId) => // (4)
                   context.log.info("Started {}", taskId)
                   Behaviors.same
                 case Backend.JobProgress(taskId, progress) =>
@@ -164,7 +164,7 @@ class InteractionPatterns3Spec extends 
ScalaTestWithActorTestKit with AnyWordSpe
             }
 
             active(inProgress = Map.empty, count = 0)
-          }.narrow
+          }.narrow // (5)
       }
       // #adapted-response
 
diff --git 
a/docs/src/main/paradox/typed/handling-actor-responses-with-scala3.md 
b/docs/src/main/paradox/typed/handling-actor-responses-with-scala3.md
new file mode 100644
index 0000000000..5f5cee9092
--- /dev/null
+++ b/docs/src/main/paradox/typed/handling-actor-responses-with-scala3.md
@@ -0,0 +1,44 @@
+# Handling responses in Scala 3
+
+Handling responses from other actors in Scala 3 is straightforward and in 
contrast with
+Scala 2, it doesn't require the utilisation of message adapters and response 
wrappers.
+
+A distinction exists between an actor's public protocol (`Command `) and its 
internal
+protocol (`CommandAndResponse`). The latter is the union of the public 
protocol and all
+the responses the actor should understand. This is union is implemented with 
Scala 3's
+Union types.
+
+**Example:**
+
+![adapted-response.png](./images/adapted-response-scala-3.png)
+
+Scala
+:  @@snip 
[InteractionPatternsSpec.scala](/actor-typed-tests/src/test/scala-3/docs/org/apache/pekko/typed/InteractionPatterns3Spec.scala)
 { #adapted-response }
+
+Let's have a look at the key changes with respect to the Pekko typed 
implementation in
+Scala 2 (see the corresponding numbering in the example code).
+
+* The type `CommandAndResponse` is the union of `Command` and 
`Backend.Response` (1)
+* In the factory method (2) for the `Behavior` of the frontend actor, a
+  `Behavior[CommandAndResponse]` is narrowed (5) to a `Behavior[Command]`. 
This works as
+  the former is able to handle a superset of the messages that can be handled 
by the latter.
+* The sending actor just sends its `self` @apidoc[actor.typed.ActorRef] in the 
`replyTo`
+  field of the message (3)
+* Responses are handled in a straightforward manner (4)
+
+A more in-depth explanation of the concepts used in applying Scala 3's Union 
types can
+be found in the following blog posts:
+
+* [Using Dotty Union types with Akka 
Typed](https://blog.lunatech.com/posts/2020-02-12-using-dotty-union-types-with-akka-typed)
+* [Using Dotty Union types with Akka Typed - Part 
II](https://blog.lunatech.com/posts/2020-02-19-using-dotty-union-types-with-akka-typed-part-II)
+
+**Useful when:**
+
+ * Subscribing to an actor that will send [many] response messages back
+
+**Problems:**
+
+ * It is hard to detect that a message request was not delivered or processed
+ * Unless the protocol already includes a way to provide context, for example 
a request id
+   that is also sent in the response, it is not possible to tie an interaction 
to some
+   specific context without introducing a new, separate, actor
\ No newline at end of file
diff --git a/docs/src/main/paradox/typed/images/adapted-response-scala-3.png 
b/docs/src/main/paradox/typed/images/adapted-response-scala-3.png
new file mode 100644
index 0000000000..1e9ec17684
Binary files /dev/null and 
b/docs/src/main/paradox/typed/images/adapted-response-scala-3.png differ
diff --git a/docs/src/main/paradox/typed/index.md 
b/docs/src/main/paradox/typed/index.md
index e0b096faa8..b162cf62e5 100644
--- a/docs/src/main/paradox/typed/index.md
+++ b/docs/src/main/paradox/typed/index.md
@@ -10,6 +10,7 @@ project.description: Using Apache Pekko to build reliable 
multi-core application
 * [actors](actors.md)
 * [actor-lifecycle](actor-lifecycle.md)
 * [interaction patterns](interaction-patterns.md)
+* [handling responses with Scala 3](handling-actor-responses-with-scala3.md)
 * [fault-tolerance](fault-tolerance.md)
 * [actor-discovery](actor-discovery.md)
 * [routers](routers.md)
diff --git a/docs/src/main/paradox/typed/interaction-patterns.md 
b/docs/src/main/paradox/typed/interaction-patterns.md
index 6c2506d120..fac3197166 100644
--- a/docs/src/main/paradox/typed/interaction-patterns.md
+++ b/docs/src/main/paradox/typed/interaction-patterns.md
@@ -103,7 +103,8 @@ Java
  
 **Problems:**
 
- * Actors seldom have a response message from another actor as a part of their 
protocol (see @ref:[adapted response](#adapted-response))
+ * Actors seldom have a response message from another actor as a part of their 
protocol as it can be considered
+   as polluting that protocol with a message from another actor's message (see 
@ref:[adapted response](#adapted-response))
  * It is hard to detect that a message request was not delivered or processed 
(see @ref:[ask](#request-response-with-ask-between-two-actors))
  * Unless the protocol already includes a way to provide context, for example 
a request id that is also sent in the
    response, it is not possible to tie an interaction to some specific context 
without introducing a new,
@@ -112,7 +113,13 @@ Java
 
 ## Adapted Response
 
-Most often the sending actor does not, and should not, support receiving the 
response messages of another actor. In such cases we need to provide an 
@apidoc[actor.typed.ActorRef] of the right type and adapt the response message 
to a type that the sending actor can handle.
+Most often the sending actor does not, and should not, support receiving the 
response messages of another actor.
+
+In such cases we need to provide an @apidoc[actor.typed.ActorRef] of the right 
type and adapt the response message
+to a type that the sending actor can handle. In the case of Scala, we need to 
make a distinction between Scala 2
+and Scala 3. In the latter case, we can actually get rid of the need to adapt 
the response message by leveraging
+Scala 3's Union types, which vastly simplifies the handling of responses. The 
details can be found in the
+section @ref:[Handling actor responses in Scala 
3](handling-actor-responses-with-scala3.md).
 
 **Example:**
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to