Search code examples
scalaimplicitscala.jsscala.rxscalatags

Ambiguous overloading: fix it or try something else?


Background: I'm working on using scala.js/scalatags together with scala.rx. What I'm trying to achieve is binding values from html inputs to Rx Vars, using operator style. Here's what I'm up to:

implicit class BoundHtmlInput(input: Input) {
  def bindTextTo(v: Var[String]): Input = {
    input.oninput = { (e: dom.Event) => v() = input.value}
    input
  }

  def bindNumberTo(v: Var[Int]): Input = {
    input.oninput = {(e: dom.Event) => v() = input.valueAsNumber}
    input
  }

  def ~>[T](v: Var[T])(implicit ev: T =:= Int): Input =
     bindNumberTo(v.asInstanceOf[Var[Int]])

  def ~>[T](v: Var[T])(implicit ev: T =:= String): Input = 
     bindTextTo(v.asInstanceOf[Var[String]])
}

It works fine for the method calls, but fails for operator ~> call. The error is following:

Error:(43, 70) ambiguous reference to overloaded definition,
both method ~> in class BoundHtmlInput of type [T](v: rx.Var[T])(implicit ev: =:=[T,String])org.scalajs.dom.html.Input
and  method ~> in class BoundHtmlInput of type [T](v: rx.Var[T])(implicit ev: =:=[T,Int])org.scalajs.dom.html.Input
match argument types (rx.core.Var[String])

And I'm not happy about the usage of asInstanceOf either.

I hope this provides enough context. My question is, what is the better way to achieve what I want?


Solution

  • Use Var[Int] and Var[String] directly, with dummy implicits to fight off double-def-after-erasure:

    def ~>[T](v: Var[Int]): Input =
      bindNumberTo(v)
    
    def ~>[T](v: Var[String])(implicit dummy: DummyImplicit): Input = 
      bindTextTo(v)
    

    You can add as many DummyImplicits as necessary, if you have more types to deal with:

    def ~>[T](v: Var[Boolean])(implicit dummy1: DummyImplicit,
        dummy2: DummyImplicit): Input = 
      bindBooleanTo(v)