bbarker
bbarker

Reputation: 13108

How to employ type member constraints for use with type classes?

I have a function with signature currently like so:

  def runInSystem[J](job: J)
  (implicit ev: Job[J] {type M <: SysJobMetaData},
   asys: ActorSystem, jobContextService: JobContextService
  ): IO[Nothing, RunResult] = ...

When I call this function like this:

  case cmd: OneShot =>
    memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)(jobOneShot, asys, jobContextService)))
    cmd

I get an error:

[error] /home/brandon/workspace/CCRS/web-server/src/main/scala/org/xsede/jobrunner/server/InMemService.scala:65: type mismatch;
[error]  found   : org.xsede.jobrunner.model.ModelApi.OneShot.jobOneShot.type (with underlying type org.xsede.jobrunner.model.ModelApi.Job[org.xsede.jobrunner.model.ModelApi.OneShot])
[error]  required: org.xsede.jobrunner.model.ModelApi.Job[org.xsede.jobrunner.model.ModelApi.OneShot]{type M <: org.xsede.jobrunner.model.ModelApi.SysJobMetaData}
[error]         memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)(jobOneShot, asys, jobContextService)))

This error doesn't make a lot of sense to me, so I wonder if I've hit a limitation in Scala's type system. The reason is that OneShot and its typeclass instance are defined as:

  final case class OneShot(id: JobId, cmd: String, meta: SysJobMetaData) {
    type M = SysJobMetaData
  }

implicit val jobOneShot: Job[OneShot] = new Job[OneShot] {
  def id(jb: OneShot): JobId = jb.id
  def cmd(jb: OneShot): String = jb.cmd
  override type M = SysJobMetaData
  def meta(jb: OneShot): M = jb.meta
}

So by definition,the constraint type M <: SysJobMetaData should be satisfied, I would think.

Upvotes: 0

Views: 44

Answers (1)

Dmytro Mitin
Dmytro Mitin

Reputation: 51703

You should declare type of implicit val correctly.

Try

implicit val jobOneShot: Job[OneShot] { type M = SysJobMetaData } = new Job[OneShot] {
  def id(jb: OneShot): JobId = jb.id
  def cmd(jb: OneShot): String = jb.cmd
  override type M = SysJobMetaData
  def meta(jb: OneShot): M = jb.meta
}

Upvotes: 1

Related Questions