简体   繁体   中英

Type error in Scala Cake Pattern

I have the following cake pattern:

// The framework
trait Frame[R] {
  def renderer:ReadRender[R]
  trait ReadRender[R] {      // <<<--- error
    def say[T](src:R) : T
  }
}

// A specific implementation
trait StringFrame extends Frame[String] {
  def renderer = new StringReadRender()
  class StringReadRender() extends ReadRender[String] {
    def say[T](src:String) : T = {
      println("Say: "+src)
      null.asInstanceOf[T]  // placeholder--actual work here in real code
    }
  }
}

// Wiring it up
trait SJ[R] {
  this : Frame[R] =>
    def foo[T](me:R) = {
      println("In foo")
      renderer.say[T](me)  
    }
}

case class Greg() extends SJ[String] with StringFrame

With default compiler settings this compiles clean and seems to work. If I enable -Xlint I get this error on the marked line above:

type parameter R defined in trait ReadRender shadows type R defined in trait ReadRenderFrame. You may want to rename your type parameter, or possibly remove it.

This pattern is designed for a JSON parser to allow a mixin trait for injection supporting different types of source data--string default but could be a byte stream or Map.

I'm worried its complaining with the -Xlint scrutiny turned on--and it makes me wonder if what seems to work without -Xlint is really safe or if I just need to be more specific somehow?

Your definition of Frame[R] is currently equivalent to the following:

trait Frame[R] {
  def renderer:ReadRender[R]
  trait ReadRender[R1] {      // Defining a new type parameter
    def say[T](src:R1) : T
  }
}

So linter is complaining, that the type parameter of ReadRender[R] is called the same as the type parameter of Frame[R] . And they are actually always the same in the provided code by definition: def renderer:ReadRender[R] . So you can throw away the type parameter of ReadRender completely, and use the type parameter of Frame instead of it:

// The framework
trait Frame[R] {
  def renderer:ReadRender
  trait ReadRender {
    def say[T](src:R) : T     // R is provided by Frame[R]
  }
}

// A specific implementation
trait StringFrame extends Frame[String] {        // Setting R to String
  def renderer = new StringReadRender()
  class StringReadRender() extends ReadRender {  // R is equal to String here
    def say[T](src:String) : T = {
      println("Say: "+src)
      null.asInstanceOf[T]  // placeholder--actual work here in real code
    }
  }
}

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