Search code examples
scalascalaz

How to preserve original type in match without resorting to asInstanceOf?


The below code is using ZIO, so I've added the scalaz tag, though that may be a bit beside the point. I have a function that takes a type J with a typeclass constraint (Job):

  def execJvm2[J: Job](cmdIn: J): IO[Nothing, Future[RunResult]] = {
    type IOJob = IO[Nothing, J]
    val cmd0: IOJob = omitted(cmdIn)
    val cmd1: IOJob = cmd0.map {
      case cmd : OneShot =>
        memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)))
        cmd.asInstanceOf[J]
      case cmd: Repl =>
        memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)))
        cmd.asInstanceOf[J]
      case cmd: ExecFile =>
        memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)))
        cmd.asInstanceOf[J]
      case _ => ???
    }
    cmd1.map { cmd => poll(cmd.id) }
  }

The examples in the pattern match (OneShot, Repl, ExecFile) all are instances of Job and have their implicit typeclass instances in scope, though I guess that is a bit beside the point. The main reason this should work without using asInstanceOf, to my thinking, is that the type has only been narrowed down in the pattern match from J to e.g. OneShot, but I would think the compiler would know it is still a J as well.


Solution

  • It looks a bit worse, but I think

    val cmd1: IOJob = cmd0.map { cmdJ => cmdJ match {
      case cmd: OneShot =>
        memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)))
        cmdJ
      case cmd: Repl =>
        memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)))
        cmdJ
      case cmd: ExecFile =>
        memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)))
        cmdJ
      case _ => ???
    }}
    

    should work. And cheating with type erasure a bit, I think this should compile and work (but try it):

    val cmd1: IOJob = cmd0.map {
      case cmd: OneShot with J @unchecked =>
        memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)))
        cmd
      case cmd: Repl with J @unchecked =>
        memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)))
        cmd
      case cmd: ExecFile with J @unchecked =>
        memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)))
        cmd
      case _ => ???
    }