Reputation: 33
I have the following code
import scala.collection.mutable
import scala.reflect.ClassTag
import scala.reflect._
object EventManager {
var handlers: Map[Class[_ <: Event], mutable.Set[EventHandler[_ <: Event]]] = Map()
def registerHandler [A <: Event](handler: EventHandler[A])(implicit tag: ClassTag[A]): Unit = {
val typeParam = tag.runtimeClass.asSubclass(classOf[Event])
handlers.get(tag.runtimeClass.asSubclass(classOf[Event])) match {
case Some(_) => handlers(typeParam) += handler.asInstanceOf[EventHandler[Event]]
case None => handlers += (typeParam -> mutable.Set(handler))
}
}
//Returns true if the event was cancelled, false otherwise
def fireEvent[A <: Event](event: A)(implicit tag: ClassTag[A]): Boolean = {
val typeParam = tag.runtimeClass.asSubclass(classOf[Event])
event match {
case cEvent: CancellableEvent =>
handlers.get(typeParam) match {
case Some(s) =>
s.foreach(handler => if (!cEvent.cancelled) handler.handle(event.asInstanceOf[_ <: Event]))
case None =>
}
//Return if the event was cancelled or not
cEvent.cancelled
case _ =>
handlers.get(typeParam) match {
case Some(s) => s.foreach(_.handle(event.asInstanceOf[_ <: Event]))
case None =>
}
false
}
}
}
trait Event
trait EventHandler[A <: Event]{
def handle(event: A)
}
trait CancellableEvent extends Event{
var cancelled: Boolean = false
}
It's intended to be a simple event handling system, although I cannot manage to figure out how to fix this annoying error I am getting.
Error:(31, 91) unbound wildcard type
s.foreach(handler => if (!cEvent.cancelled) handler.handle(event.asInstanceOf[_ <: Event]))
I honestly have no Idea what I could do to fix this. Also, I haven't been working with Scala that long so if you have any suggestions on how to make my code more idiomatic feel free!
Upvotes: 2
Views: 1677
Reputation: 30453
The shortest path I can see to making your code compile is:
- s.foreach(handler => if (!cEvent.cancelled) handler.handle(event.asInstanceOf[_ <: Event]))
+ s.foreach{case handler: EventHandler[t] =>
+ if (!cEvent.cancelled) handler.handle(event.asInstanceOf[t])}
- case Some(s) => s.foreach(_.handle(event.asInstanceOf[_ <: Event]))
+ case Some(s) =>
+ s.foreach{case handler: EventHandler[t] =>
+ handler.handle(event.asInstanceOf[t])}
But, I wonder why you even bother with the type parameter on EventHandler
at all. The way you're using it provides no safety at compile time. The type parameter is always existential, so the compiler has no idea what the actual type is, so all the compiler can do is refuse to sign off because it doesn't have enough information to assure you the code is safe, forcing you to override it with asInstanceOf
.
I think you should choose one of two paths forward:
asInstanceOf
escape hatch. Don't use scala.reflect
, don't use java.lang.Class
, don't use ClassTag
— all of these things can fail at runtime.What you have at the moment just seems like an mish-mash to me — Java reflection, Scala reflection, type parameters, pattern matching, all jumbled up in a way that doesn't seem to be the product of coherent thinking about what you want to happen at compile-time vs at run-time. The lack of coherence makes it difficult to even critique without writing a much longer answer than this.
Upvotes: 1