pjfanning opened a new issue, #3750:
URL: https://github.com/apache/pekko/issues/3750

   ### Summary
   
   The wildcard bounds added to the typed Java DSL in #3720 stop Scala 2.13 
callers from passing a function literal to overloaded methods such as 
`CommandHandlerBuilderByState.onCommand` and 
`EventHandlerBuilderByState.onEvent`. Code that compiled against 2.0.0-M4 fails 
against 2.0.0.
   
   Java callers and Scala 3 callers are not affected. This came up in 
`grpc-int-test` while updating pekko-projection to 2.0.0 
(apache/pekko-projection#674). Calling the Java DSL from Scala is unusual, so 
this may only need documenting, but it is a source incompatibility for anyone 
who does it.
   
   ### Reproducer with Pekko
   
   ```scala
   import org.apache.pekko.persistence.typed.PersistenceId
   import org.apache.pekko.persistence.typed.javadsl._
   
   object Repro {
     sealed trait Command
     final case class Get() extends Command
     final case class Changed()
     final case class State()
   
     class Behavior(id: PersistenceId) extends EventSourcedBehavior[Command, 
Changed, State](id) {
       override def emptyState: State = State()
   
       override def commandHandler(): CommandHandler[Command, Changed, State] =
         newCommandHandlerBuilder()
           .forAnyState()
           .onCommand(classOf[Get], { (state: State, command: Get) => 
Effect.none() })
           .build()
   
       override def eventHandler(): EventHandler[State, Changed] =
         newEventHandlerBuilder()
           .forAnyState()
           .onEvent(classOf[Changed], { (state: State, event: Changed) => state 
})
           .build()
     }
   }
   ```
   
   ```shell
   scala-cli compile -S 2.13.18 --dep 
"org.apache.pekko::pekko-persistence-typed:2.0.0" Repro.scala
   ```
   
   ```
   error: overloaded method onCommand with alternatives:
     [C <: Repro.Command](commandClass: Class[C], handler: 
java.util.function.BiFunction[_ >: Repro.State, _ >: C, _ <: 
...Effect[Repro.Changed,Repro.State]]): ... <and>
     (predicate: java.util.function.Predicate[_ >: Repro.Command],handler: 
java.util.function.BiFunction[_ >: Repro.State, _ >: Repro.Command, _ <: 
...Effect[Repro.Changed,Repro.State]])...
    cannot be applied to (Class[Repro.Get], (Repro.State, Repro.Get) => 
...EffectBuilder[Repro.Changed,Repro.State])
   ```
   
   ### Reduced reproducer without Pekko
   
   ```scala
   import java.util.function.{ BiFunction, Predicate }
   
   object Repro {
     trait Cmd; class Get extends Cmd; class St; class Eff; class EffB extends 
Eff
     class Builder[S] {
       def on[C <: Cmd](c: Class[C], f: BiFunction[_ >: S, _ >: C, _ <: Eff]): 
Unit = ()
       def on(p: Predicate[_ >: Cmd], f: BiFunction[_ >: S, _ >: Cmd, _ <: 
Eff]): Unit = ()
     }
     new Builder[St].on(classOf[Get], { (s: St, g: Get) => new EffB })
   }
   ```
   
   | Variant of the reduced reproducer | Scala 2.13.18 | Scala 3.3.9 |
   |---|---|---|
   | Overloaded, wildcard bounds (above) | fails | compiles |
   | Overloaded, no wildcards (`BiFunction[S, C, Eff]`, `Predicate[Cmd]`) | 
compiles | compiles |
   | Only the `Class[C]` method, wildcard bounds, no overload | compiles | 
compiles |
   
   So the failure needs both overloading and wildcard bounds. Neither one fails 
alone.
   
   ### Results
   
   | Caller | 2.0.0-M4 | 2.0.0 |
   |---|---|---|
   | Scala 2.13.18, function literal | compiles | **fails** |
   | Scala 3.3.9, function literal | not tested | compiles |
   | Java 17, lambda (inferred or explicit parameter types) | compiles | 
compiles |
   | Java 17, pre-typed `BiFunction<Object, Command, Effect<Changed, State>>` | 
fails | compiles |
   
   The last row is the case #3720 set out to enable, so the widening does what 
it intended for Java.
   
   ### Workaround for Scala 2.13
   
   Ascribe each function literal to a concrete `BiFunction` type. This compiles 
on Scala 2.13.18 and 3.3.9:
   
   ```scala
   import java.util.function.BiFunction
   
   newCommandHandlerBuilder()
     .forAnyState()
     .onCommand(classOf[Get],
       { (state: State, command: Get) => Effect.none() }: BiFunction[State, 
Get, Effect[Changed, State]])
     .build()
   
   newEventHandlerBuilder()
     .forAnyState()
     .onEvent(classOf[Changed], { (state: State, event: Changed) => state }: 
BiFunction[State, Changed, State])
     .build()
   ```
   
   An explicit type argument is not enough. `.onCommand[Get](classOf[Get], 
...)` and `.onEvent[Changed](classOf[Changed], ...)` still fail against 2.0.0, 
because `BiFunction`, `Function` and `Supplier` overloads all take a `Class[C]`.
   
   ### Scope and open question
   
   Only the `BiFunction` overloads of `onCommand` and `onEvent` were tested. 
#3720 widened other typed Java DSL methods, and overloaded ones may behave the 
same way from Scala 2.13.
   
   Should this be documented as a known limitation, for example in the 
migration notes, or is there a way to keep these overloads usable from Scala 
2.13 without giving up the widening for Java?
   


-- 
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