lihaoyi / autowire

Macros for simple/safe RPCs between Scala applications, including ScalaJS/ScalaJVM
378 stars 48 forks source link

Possible issue using ClassTag in autowire calls #68

Open bbarker opened 7 years ago

bbarker commented 7 years ago

I had a working API that looked like

final case class OneShot(id: CommandId, body: String, meta: SysCmdMetaData)
extends Command[SysCmdMetaData]

def exec(data: List[OneShot]): Future[List[RunResult]]

with the js implementation of exec being:

  def exec(cmds: List[OneShot]): Rx[List[RunResult]] = {
    println("Verifying outer exec is called")
    AutowireClient[Api].exec(cmds).call().toRx.map {
      case Some(attempt) => attempt match {
        case Success(output) => output
        case Failure(err) =>
          List(RunResult.fakeResult(s"Error: ${err.getCause}!", NONFATAL_APP_ERR))
      }
      case None => List(RunResult.fakeResult(""))
    }
  }

In an attempt to generify things a bit, I changed the API's exec signature to:

  def exec[M <: CommandMetaData : ClassTag, C <: Command[M] : ClassTag]
  (data: List[C]): Future[List[RunResult]]

and the implementation to:

  def exec[M <: CommandMetaData : ClassTag, C <: Command[M] : ClassTag]
  (cmds: List[C]): Rx[List[RunResult]] = {
    println("Verifying outer exec is called")
    AutowireClient[Api].exec[M, C](cmds).call().toRx.map {
      case Some(attempt) => attempt match {
        case Success(output) => output
        case Failure(err) =>
          List(RunResult.fakeResult(s"Error: ${err.getCause}!", NONFATAL_APP_ERR))
      }
      case None => List(RunResult.fakeResult(""))
    }
  }

This results in the compile error:


You can't call the .call() method on autowire.`package`.unwrapClientProxy[model.Api, java.nio.ByteBuffer, boopickle.Default.Pickler, boopickle.Default.Pickler](client.AutowireClient.apply[model.Api]).exec[M, C](cmds)(evidence$1, evidence$2), only on autowired function calls.
[error]     AutowireClient[Api].exec[M, C](cmds).call().toRx.map {```
bbarker commented 6 years ago

Here's a workaround I ended up using. I got rid of all the type parameters, and just used type members instead, passing in subclasses that have the requisite type members as necessary to help with type inference.