简体   繁体   中英

How can I override a type member of a class with the same base class?

Sorry for the confusing title.

I am attempting to write some Request and Response classes for validation and parsing purposes. I'd like to have some guarantees of the type at compile-time, but still have runtime polymorphism. I have the following base classes:

abstract class Response()

abstract class Request() {
  type ResponseType = Response
  def ResponseClass: Class[_ <: ResponseType] = classOf[ResponseType]
}

so if I have an instance of type _ <: Request , I can parse, for instance a JSON response, with the correct type: Json.parse(responseString).as[request.ResponseType] .

I find that when I extend these classes, I am unable to override the ResponseType :

case class AddedFooResponse() extends Response

case class AddFooRequest() extends Request {
  override type ResponseType = AddedFooResponse
}

error: overriding type ResponseType in class Request , which equals this.Response ; type ResponseType has incompatible type override type ResponseType = AddedFooResponse

I am unsure why the types are incompatible. My current workaround is a bit clumsy, which is to bound the type in the base classes:

abstract class Response()

abstract class Request() {
  type ResponseType <: Response
  // cannot initialize because no concrete class
  def ResponseClass: Class[_ <: ResponseType] 
}

and simply override both the ResponseType and the ResponseClass :

case class AddedFooResponse() extends Response

case class AddFooRequest() extends Request {
  override type ResponseType = AddedFooResponse
  override def ResponseClass = classOf[ResponseType]
}

This requires a lot of (seemingly) unnecessary boilerplate for overriding the ResponseClass .

What am I doing incorrectly?

I think you could get away by not setting a default value for this type:

abstract class RequestBase() {
  type ResponseType
  def ResponseClass: Class[_ <: ResponseType] = classOf[ResponseType]
}

type Request = RequestBase { type ResponseType = Response }

case class AddFooRequest() extends Request {
  override type ResponseType = AddedFooResponse
}

I found that I can forego completely the ResponseClass by simply setting the ResponseType and matching based on the instance returned by whatever uses that ResponseType , lest it'll parse incorrectly and throw an exception.

abstract class Response
abstract class Request[+ResponseType <: Response]

case class FooResponse() extends Response {
  def greet = println("woo hoo!")
}

case class FooRequest() extends Request[FooResponse] {
  type ResponseType = FooResponse
}

val req: FooRequest = new FooRequest()
// Erase the type by making it an Object.
val resp: Object = new FooResponse()

resp.asInstanceOf[req.ResponseType] match {
  case fooResp: FooResponse => fooResp.greet
  case _ => println("This isn't good...")
}

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