Combining F-bound polymorphism with inheritance in Scala

Combining F-bound polymorphism with inheritance in Scala
I'm learning Scala. As part of this learning, I decided to build a type system for events. An object (any class via a trait or a typeclass) can have multiple subscribers to events (events are strings for now). A subscriber (or a handler) is an object wrapping a function. The handler should be contravariant, as in, an object can have subscribers tied to its own type or any of its parent types (think how a button can have button-specific handlers, but also handlers for a generic widget). This is the Handler type definition: class Handler[-A](val name: String = null)(val fn: A => Unit) { def apply(obj: A): Unit = fn(obj) } So I've ran straight into the famous "type of self" problem. I tried to solve it with F-bound polymorphism: trait Eventable[A <: Eventable[A]] { this: A => private val subscribers = mut.HashMap[String, mut.Buffer[Handler[A]]]() def subscribe(event: String, handler: Handler[A]): Unit = { subscribers.getOrElseUpdate(event, ArrayBuffer()).append(handler) } def fireEvent(event: String): Unit = { subscribers.get(event).foreach{subs => for(sub <- subs) { sub(this) } } } } object Eventable { def fireAll(event: String, eventables: Seq[? <: Eventable[?]]): Unit = { for(e <- eventables) { e.fireEvent(event) } } } The problem is that this doesn't work with inheritance: class Thing(val name: String) extends Eventable[Thing] class Gadget(name: String, val temp: Int) extends Thing(name) // ... val thing = Thing("Item") val gadget = Gadget("Gadget", 85) val handler1 = Handler() { (a: Thing) => println(a.name) } val handler2 = Handler() { (a: Object) => println(a.hashCode()) } val handler4 = Handler("GadgetHandler"){ (a: Gadget) => println(s"${a.name} [${a.temp}]") } thing.subscribe("evt", handler1) thing.subscribe("evt", handler2) // gadget.subscribe("evt", handler4) — This doesn't compile because gadget wants Handler[Thing] And I can't define Gadget to extend Thing(name) with Eventable[Gadget] because of conflicting bases. Is there any way to solve this?

Take Your Experience to the Next Level

New

Download our mobile app for a faster and better experience.

Comments

0
U

Join the discussion

Sign in to leave a comment

0:000:00