Is the Dotty compilation bevaiour correct: No ClassTag available for Nothing

I am experimenting with Akka and have the following code snippet:

    private val behavior = Behaviors.supervise(SupervisedActor()).onFailure(SupervisorStrategy.restart)

And I get a:

No ClassTag available for Nothing

on the onFailure method.

I can solve this as follows (verbose typing to make things clear):

    private val strategy: Behaviors.Supervise[String] = Behaviors.supervise(SupervisedActor())
    private val behavior: Behavior[String] = strategy.onFailure[Throwable](SupervisorStrategy.restart)
    private val child = context.spawn(behavior, name = "supervised-actor")

Now if we look at the source code we see:

  private final val ThrowableClassTag = ClassTag(classOf[Throwable])
  final class Supervise[T] private[akka] (val wrapped: Behavior[T]) extends AnyVal {

    /** Specify the [[SupervisorStrategy]] to be invoked when the wrapped behavior throws. */
    def onFailure[Thr <: Throwable: ClassTag](strategy: SupervisorStrategy): Behavior[T] = {
      val tag = classTag[Thr]
      val effectiveTag = if (tag == ClassTag.Nothing) ThrowableClassTag else tag
      Supervisor(Behavior.validateAsInitial(wrapped), strategy)(effectiveTag)
    }
  }

So it seems like if we don’t make the type explicit, the library designers set the exception for us.

So my questions are:

  • why does Dotty force us to provide these tags?
  • seeing as it is an implicit, is their any way to set this via an implicit val?

TIA

Dotty intentionally tries to prevent you from using a ClassTag[Nothing] because of soundness issues: https://github.com/lampepfl/dotty/issues/1730
Apparently akka is using a ClassTag of Nothing as a marker to mean “we didn’t find a classtag, let’s use a default one”, I think a better alternative to do that which would also work with dotty would be to simply use a default argument:

    def onFailure[Thr <: Throwable](strategy: SupervisorStrategy)(implicit tag: ClassTag[Thr] = ThrowableClassTag): Behavior[T] = {
      Supervisor(Behavior.validateAsInitial(wrapped), strategy)(tag)
    }

Someone please make a PR to akka with this change :).

Thanks for the link and information.