2

The intended output of the following code is the digit, 0.

object Bad extends App {
  implicit val massTable: Map[String, Int] =
    Map("H" -> 1, "He" -> 4, "O" -> 16)

  Implementation.doWork()
}

object Implementation {
  def doWork()(implicit massTable: Map[String, Int]) = println("0".toInt)
}

The actual output is an exception:

java.util.NoSuchElementException: key not found: 0
at scala.collection.immutable.Map$Map3.apply(Map.scala:156)
at Implementation$.doWork(Main.scala:20)
at Bad$.delayedEndpoint$Bad$1(Main.scala:16)
...

Investigation shows that Map implements apply(string): Int causing the implicit parameter supplied to doWork, massTable, to also and unintentionally function as an implicit conversion from String => Int.

The result is that, the above toInt call is the synthetic method toInt for the type Int, rather than the toInt method provided by StringOps.

What is the best way to avoid this sort of issue and achieve the desired output?

vossad01
  • 11,552
  • 8
  • 56
  • 109
  • 2
    Wrap your implicit `Map` in a case class. – Reactormonk Jan 06 '17 at 00:01
  • 5
    This is just one of many, many reasons not to use implicit scope as a place to tuck away data. – Travis Brown Jan 06 '17 at 00:22
  • I am with Travis here. Don't use implicit parameters to simply pass parameters to you as a DI container would do. – pedrofurla Jan 06 '17 at 00:57
  • 1
    It's hard to convince people not to use implicit scope as configuration source when standard library and popular libraries do just that (`ExecutionContext`, `ActorMaterializer`, ...). Usually the compromise is to define implicits only for some very specific type that you own. – Haspemulator Jan 06 '17 at 11:11

0 Answers0