Erasure of type fields

Refresh

December 2018

Views

34 time

2
abstract class Handler {
  type Message

  def handleAny(msg: Any) {
    if (msg.isInstanceOf[Message]) handle(msg.asInstanceOf[Message]) // fix me!
  }

  def handle(msg: Message)
}

class StringHandler extends Handler {
  override type Message = String

  def handle(msg: Message) { println(s"handling: $msg") }
}

val h = new StringHandler
h.handleAny("ahoj")
h.handleAny(true)

warning: abstract type Handler.this.Message is unchecked since it is
 eliminated by erasure
                if(msg.isInstanceOf[Message]) handle(msg.asInstanceOf[Message])
                                   ^
one warning found
handling: ahoj
java.lang.ClassCastException: java.lang.Boolean cannot be cast to java.lang.String
        at Main$$anon$1$StringHandler.handle(typeProblem.scala:11)
        at Main$$anon$1$Handler.handleAny(typeProblem.scala:5)

How to change the snippet (without changing interface or replacing type field with type parameter) to work as expected, which is to handle only messages specified by the type field?

I'm looking for a solution which can be applied to the parent abstract class rather than polluting all children.

I also tried to use a match and it behaves exactly same. Or is this kind of thing impossible with type fields (I thought they are more powerful than type parameters)?

1 answers

2

Один , как правило , использует матч и в вашем случае, как вы не хотите , чтобы добавить какие - либо параметры типа вы должны будете указать ClassTag(я думаю).

Что-то вдоль линий:

import scala.reflect.ClassTag

abstract class Handler {
  type Message <: Any
  implicit val tag: ClassTag[Message]

  def handleAny(msg: Any): Unit = {
    msg match {
      case tag(message) =>
        handle(message)
      case _ =>
        throw new IllegalArgumentException(s"Argmument MUST BE a 'Message' but $msg is not!")
    }
  }

  def handle(msg: Message): Unit
}

object StringHandler extends Handler {
  override type Message = String
  // lazy is important here!
  implicit lazy val tag: ClassTag[Message] = ClassTag(classOf[String])

  def handle(msg: Message): Unit =  { println(s"handling: $msg") }
}


StringHandler.handleAny("ahoj")
StringHandler.handleAny(true)