简体   繁体   中英

Implicitly wrapped trait with type member does not compile

The following does not compile because of the last line:

object ImplicitWrappedTraitWithType {

  trait Wrapper[+T] {
    def unwrap: T
  }

  object Wrapper {
    def apply[T](implicit w: Wrapper[T]): Wrapper[T] = w
  }

  trait IO[In] {
    type Out

    def out: Out
  }

  implicit def decoder[In]: Wrapper[IO[In] {type Out = String}] = new Wrapper[IO[In] {type Out = String}] {
    override def unwrap: IO[In] {type Out = String} = new IO[In] {
      override type Out = String
      override val out: Out = "yeah"
    }
  }

  val wrap = Wrapper[IO[String]]
  val io: IO[String] = wrap.unwrap
  val out: String = io.out //actual type: unwrap.Out
}

What can I do to convince the compiler that val out is a String ?


Pre-edit - ignore this

Example 1 - this does not compile:

object ImplicitWrappedTraitWithType {
  class Wrapper[T]
  object Wrapper {
    def apply[T](implicit w: Wrapper[T]): Wrapper[T] = w
  }
  trait IO[In] {
    type Out
  }
  implicit def decoder[In]: Wrapper[IO[In] {type Out = String}] = null

//client code
  Wrapper[IO[String]]
}

Example 2 - whereas this does:

object ImplicitWrappedTraitWithType {
  class Wrapper[T]
  object Wrapper {
    def apply[T](implicit w: Wrapper[T]): Wrapper[T] = w
  }
  trait IO[In] {
    type Out
  }
  implicit def decoder[In]: Wrapper[IO[In]] = null

//client code
  Wrapper[IO[String]]
}

In the client code I don't know what the type of Out will be, but I need to be able to access it when I extract an instance of IO from Wrapper (code for that not shown).

How must 'Example 1' be changed for this to compile, while retaining the Out parameter in a way that is visible for the client code.

(Please comment if this formulation is unclear)

You only need two minor edits to your code.

trait Wrapper[+T] {
  def unwrap: T
}

object Wrapper {
  def apply[T](implicit w: Wrapper[T]): w.type = w
}

trait IO[In] {
  type Out

  def out: Out
}

implicit def decoder[In]: Wrapper[IO[In] {type Out = String}] = new Wrapper[IO[In] {type Out = String}] {
  override def unwrap: IO[In] {type Out = String} = new IO[In] {
    override type Out = String
    override val out: Out = "yeah"
  }
}

val wrap = Wrapper[IO[String]]
val io = wrap.unwrap
val out: String = io.out

The most important is to change the return type of the apply method to w.type . That way the full type of w (including all refinements) is retained. If you write Wrapper[T] as return type and you ask for a Wrapper[T] for T equal to IO[String] , you will get a Wrapper[IO[String]] and all extra knowledge like {type Out = String} will be lost.

Second: in val io: IO[String] = wrap.unwrap you say that io is an IO[String] . Again, all extra knowledge is lost. So just let the compiler infer the type of io .

Another thing: if you don't want Wrapper to be covariant in T , you can just leave off the variance annotation and change your apply method.

trait Wrapper[T] {
  def unwrap: T
}

object Wrapper {
  def apply[T](implicit w: Wrapper[_ <: T]): w.type = w
}

That way the compiler still knows it has to look for a subtype of IO[String] if you call Wrapper.apply[IO[String]] . Because IO[String]{type out = String} is a subtype of IO[String] , they are not equal.

Not clear what you are trying to achieve, but does that solve your problem? (note the -T in Wrapper)

object ImplicitWrappedTraitWithType {
  class Wrapper[-T]
  object Wrapper {
    def apply[T](implicit w: Wrapper[T]): Wrapper[T] = w
  }
  trait IO[In] {
    type Out
  }
  implicit def decoder[In]: Wrapper[IO[In]] = null


}
import ImplicitWrappedTraitWithType._

trait IOString[In] extends IO[In] { 
  type Out = String
}
//client code
Wrapper[IOString[Int]]

I won't put any restriction on the Out type when trying to find an implicit decoder for it.

Whether the user defines it's own decoder and in that case you don't care about In and Out , or you have some basic decoders and you provide it, eg: IO[Int, String], IO[Int, Boolean], etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM