Vlad Miller
Vlad Miller

Reputation: 2279

Scala implicit conversions order

I have two objects with similar method ~(...). I also defined implicit conversions which should convert pair (String, A) to either DemoObject or WopWopWop

class DemoObject[A](t: (String, A)) {
  def ~(t: (String, A)) = "demo"
}

class WopWopWop[A](t: (String, A)) {
  def ~(t: AnyVal) = "wop wop wop"
}

object ImplicitDemoConversions {
  implicit def pair2DemoObject[A](t: (String, A)) = new DemoObject(t)
}

object ImplicitWopWopWopConversions {
  implicit def pair2WopWopWop[A](t: (String, A)) = new WopWopWop(t)
}

However, having something like

import ImplicitDemoConversions._
object Hello {
  def main(args: Array[String]): Unit = {
    import ImplicitWopWopWopConversions._
    val pair = ("LolTest" -> "A") ~ ("whoa" -> "wop wop wop")

    println(pair) 
  }
}

will print answer demo instead of expected wop wop wop. Looks like scala compiler ignores second import of ImplicitWopWopWopConversions._

Question is why do I think that pair (String, String) should be converted to WopWopWop and how do I get WopWopWop object instead of DemoObject?

You can find real example here https://github.com/json4s/json4s/issues/121

Upvotes: 0

Views: 121

Answers (1)

bwroga
bwroga

Reputation: 5449

You can hide the import with an alias.

import ImplicitDemoConversions.{pair2DemoObject => i}
object Hello {
  def main(args: Array[String]): Unit = {
    import ImplicitWopWopWopConversions.{pair2WopWopWop => i}
    val pair = ("LolTest" -> "A") ~ ("whoa" -> "wop wop wop")

    println(pair) 
  }
}

Edit

The reason that your tuple is being converted to a DemoObject instead of a WopWopWop is because DemoObject's ~ method argument type is more specific than WopWopWop's.

It's just like this example:

object A {
    def m(x: AnyVal) { println(x) }
    def m(x: (Int, String)) { println(x) }

    // This will call the first method, because the second method can't be
    // applied to an Int
    a(1)
    // Either method could be applied to a (Int, String), but the second 
    // method will be chosen, because it's argument type is more specific.
    a((1 -> "hello"))
}

Upvotes: 2

Related Questions