He-Pin opened a new issue, #3683:
URL: https://github.com/apache/pekko/issues/3683

   ### Motivation
   Adding `thenStop` directly to `ReplyEffect` also exposes 
`Effect.stash().thenStop()` in both persistence models and both DSLs. This 
stashes the current command and immediately stops the actor, discarding that 
command without a reply. Enforced replies do not reject it because stashing 
already returns a `ReplyEffect`.
   
   This was identified in the [review of 
#3682](https://github.com/apache/pekko/pull/3682#discussion_r4366555016). 
Instead of accepting the combination or throwing when the effect is 
constructed, we can express the permitted operations through stages in the 
public API.
   
   ### Proposed staged API
   Use a session-type-inspired staged API (also commonly described as 
typestate): each returned type exposes only the operations supported at that 
stage. This is a restriction on effect construction, not a full session type 
system for actor communication.
   
   For `thenStop`, introduce `ReplyEffectWithStop` as a subtype of 
`ReplyEffect`. The name is provisional:
   
   ```scala
   trait ReplyEffect[+Event, State] extends Effect[Event, State] {
     def thenUnstashAll(): ReplyEffect[Event, State]
   }
   
   trait ReplyEffectWithStop[+Event, State] extends ReplyEffect[Event, State] {
     def thenStop(): ReplyEffectWithStop[Event, State]
     override def thenUnstashAll(): ReplyEffectWithStop[Event, State]
   }
   ```
   
   | Operation | Returned stage |
   | --- | --- |
   | `reply`, `thenReply` | `ReplyEffectWithStop` |
   | `noReply`, `thenNoReply` | `ReplyEffectWithStop` |
   | `stash` | `ReplyEffect` |
   
   The base `ReplyEffect` must not declare `thenStop`: a subtrait cannot hide 
an inherited operation. Scala and Java, and event sourcing and durable state, 
should follow the same rules. Public traits should contain declarations; 
concrete effect implementations implement the methods.
   
   ### Expected behavior and boundaries
   - `reply(...).thenStop()` and `persist(...).thenReply(...).thenStop()` 
compile.
   - `reply(...).thenUnstashAll().thenStop()` retains the stop capability.
   - `stash().thenStop()` and `stash().thenUnstashAll().thenStop()` do not 
compile.
   - A helper that may stash returns `ReplyEffect`, so its caller cannot append 
`thenStop`. A helper whose callers need that capability must explicitly return 
`ReplyEffectWithStop`.
   - `noReply` deliberately opts out of replying and can still be followed by 
stopping.
   - This only constrains the current effect chain. Stopping can still discard 
commands stashed by earlier commands; it cannot prove that the actor's stash is 
empty or that a recipient has processed a reply.
   
   ### Compatibility and validation
   An isolated prototype using the real effect sources compiled on Scala 2.13 
and Java, accepted legal chains and rejected illegal ones. Directly narrowing 
existing factory return types changes JVM descriptors: a Java client compiled 
against the old `EffectFactories.noReply(): ReplyEffect` failed with 
`NoSuchMethodError` on that prototype. A separate one-method bridge experiment 
preserved that call, but introduced compatibility machinery.
   
   For the proposed 2.0.0 change, prefer the direct staged API and explicitly 
document the intentional binary incompatibility, rather than adding bridge 
machinery. Any MiMa exceptions must identify the exact changed signatures and 
the 2.0.0 rationale. Full repository validation remains required; the isolated 
prototype is not a substitute for CI.
   
   #3682 is being revised as the first concrete application. Once it is merged, 
a separate `thenRun` proposal should follow the same stage design, including 
whether callbacks are supported after stashing and how capability is preserved 
through callback chaining. Avoid introducing `thenRun` into #3682.
   
   Acceptance includes positive and negative compilation coverage, runtime 
reply/stop ordering, Scala/Java parity, documentation, `@since 2.0.0`, and 
remote CI including binary compatibility checks with only the agreed 
intentional changes excluded.
   
   ### Prior art
   [jOOQ's DSL 
API](https://www.jooq.org/doc/latest/manual/sql-building/dsl-api/) uses an 
interface hierarchy to express legal construction sequences. Its [guidance on 
step 
types](https://www.jooq.org/doc/latest/manual/reference/dont-do-this/dont-do-this-jooq-step-types/)
 also highlights the composition and compatibility costs of exposing those 
types in helper signatures. Those tradeoffs should be explicit in Pekko's 
design.
   
   Refs #3682.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to