I’m trying to instantiate classes from Maps[String, Any], receiving through some json-rpc.
So I end up with following problem:
val mpa:Map[String, Any] = Map("key"->0.0)
implicit def anyToInt(a:Any):Int = a.asInstanceOf[Double].toInt
When key exists all is OK.
val i:Int = mpa.getOrElse("key", 0.0)
i: Int = 0
But when key is missing …:
scala> val i:Int = mpa.getOrElse("val", 0.0)
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Double
at scala.runtime.BoxesRunTime.unboxToDouble(Unknown Source)
at .anyToInt(<console>:13
Now, if we’re add some verbosity as:
implicit def anyToInt(a:Any):Int = {
println(a)
val b = a.asInstanceOf[Double].toInt
println("converted")
b
}
We got:
val i:Int = mpa.getOrElse("val", 0.0)
0.0
converted
0
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Double
.....
So i came to the conclusion that anyToInt is called twice. And the second time it received Int as Any.
Questions:
-
Why ?!
-
What should I do to avoid this ?
P.S.: Sorry if it’s newbie question. I’m new in scala.
Having hidden direct conversions and especially for
Anyas it is in your case is a very bad idea and you’ve discovered why. I’d advice you to simply convert your input map intoMap[String, Int]. You don’t need implicits here, but if you still want to go with implicits you should do it with wrapper approach:and use it like so:
Since scala 2.10 the following implementation of implicit wrappers is preferred:
Also since your conversion function does not work on all subtypes of
Anyit is incorrect to extendAnywith such a function, it would be correct to extendDoublewith such a function but it already has it. So in your scenario the only correct way of using your map would be simply as follows:Update
Conversion to
Map[String, Int]will work for you, if you move the logic you wanted to place in implicits like so: