Scala type conversion error, need help!

I get a weird error when trying to use a Java map in Scala. This is a piece of code

val value:Double = map.get(name) if (value eq null) map.put(name, time) else map.put(name, value + time) 

mapping is defined as

 val map=new ConcurrentHashMap[String,Double] 

and this is the error i get

 error: type mismatch; found : Double required: ?{val eq: ?} Note that implicit conversions are not applicable because they are ambiguous: both method double2Double in object Predef of type (Double)java.lang.Double and method doubleWrapper in object Predef of type (Double)scala.runtime.RichDouble are possible conversion functions from Double to ?{val eq: ?} if (value eq null) map.put(name, time) 

I'm new to Scala, so it's hard for me to parse stacktrace. Any help would be appreciated

+6
scala
source share
3 answers

Firstly, map.get(name) will not return null if the name key is not on the map. Instead, it will return a Double(0.0) .

Secondly, the error you see is that scala tries to implicitly convert the returned double value to a type suitable for eq comparison, and detects more than a few implicit conversions in the area.

The best way to do what you do is

 if (map contains name) map.put(name, map.get(name) + time) else map.put(name, time) 
+5
source share
 error: type mismatch; found : Double required: ?{val eq: ?} 

The problem here is that eq is only defined for classes extending AnyRef and extending to Null , but Double extends AnyVal .

+3
source share

As Daniel wrote, part of the problem trying to write Java-style using Double is because Double in Scala is scala.Double , not java.lang.Double . If you want to program a Java style, you will need to run the following lines:

 // // a) Java style, with concurrency problem // import java.lang.{Double=>JDouble} import java.util.concurrent.ConcurrentHashMap val map = new ConcurrentHashMap[String, JDouble] def update(name: String, time: Double) { val value: JDouble = map.get(name) if (value eq null) map.put(name, time) else map.put(name, JDouble.valueOf(value.doubleValue + time)) } update("foo", 42.0d) update("foo", 41.0d) assert(map.get("foo") == 83.0d) 

Scala 2.8 contains the Scala shell for ConcurrentMap s, so you can easily avoid the java.lang.Double vs scala.Double . I will keep the program structure for a moment.

 // // b) Scala style, with concurrency problem. // import collection.JavaConversions._ import collection.mutable.ConcurrentMap import java.util.concurrent.ConcurrentHashMap val map: ConcurrentMap[String, Double] = new ConcurrentHashMap[String,Double]() def update(name: String, time: Double) { map.get(name) match { case None => map.put(name, time) case Some(value) => map.put(name, value + time) } } update("foo", 42.0d) update("foo", 41.0d) assert(map("foo") == 83.0d) 

In option b) above, there is not a single problem of representing the missing value as 0.0d, nor a problem that java.lang.Double does not play well with statements and boxing. But both versions a) and b) are questionable regarding their concurrency behavior. The Mansoor code uses ConcurrentHashMap , which aims to allow simultaneous access to the map. In the original version of the code, there is a chance that the map update will be lost between getting the old value and saving value + time . Option c) below tries to avoid this problem.

 // // c) Scala style, hopefully safe for concurrent use ;) // import collection.JavaConversions._ import collection.mutable.ConcurrentMap import java.util.concurrent.ConcurrentHashMap val map: ConcurrentMap[String, Double] = new ConcurrentHashMap[String,Double]() def update(name: String, time: Double) { val valueOption: Option[Double] = map.putIfAbsent(name, time) def replace(value: Double) { val replaced = map.replace(name, value, value + time) if (!replaced) { replace(map(name)) } } valueOption foreach { replace(_) } } update("foo", 42.0d) update("foo", 41.0d) assert(map("foo") == 83.0d) 
+1
source share

All Articles