Converting Map[String, Double] to java.util.Map[String, java.lang.Double] - scala

I thought we can rely on implicit conversion which converts scala.Double to java.lang.Double. So I tried the following:
import scala.collection.JavaConverters._
object Main extends App {
def main(args: Array[String]) = {
val m = Map("10" -> 20.0)
doSome(m.asJava) //error. Type mismatch found: java.util.Map[String,scala.Double]
// required: java.util.Map[String,java.lang.Double]
doSome2(m.asJava)
}
def doSome(m: java.util.Map[java.lang.String, java.lang.Double]) = println(m)
def doSome2(m: java.util.Map[java.lang.String, Double]) = println(m)
}
Why doesn't it work? What would be the idiomatic way to perform such a conversion?

You need the boxed version of double:
import scala.collection.JavaConverters._
m.mapValues(Double.box).asJava
The implicits are able to convert a value of Double to java.lang.Double, but not a Map[String,Double] to java.util.Map[String,java.lang.Double].
String requires no conversion because String is a java.lang.String while Double is a double (primitive).

It seems that for String, you don't need to do any conversion, but is not the case for Double.
You can use the method double2Double which is defined in Predef to convert to java.double.
import scala.collection.JavaConverters._
m.map { case (k, v) => k -> double2Double(v) }.asJava
or another way is to do asInstanceOf to convert it to Java map directly.

The issue here is that scala.Double is a primitive (equivalent to Java double) while java.lang.Double is a class. They are not at all the same thing. The JavaConverters converts between Java Map and Scala Map, not their contents. This works:
import scala.collection.JavaConverters._
object Main {
def main(args: Array[String]): Unit = {
val m = Map("10" -> 20.0)
doSome(mapConv(m))
doSome2(m.asJava)
}
def doSome(m: java.util.Map[java.lang.String, java.lang.Double]) = println(m)
def doSome2(m: java.util.Map[java.lang.String, Double]) = println(m)
def mapConv(msd: Map[String, Double]): java.util.Map[java.lang.String, java.lang.Double] = {
msd.map { case (k, v) => (k -> new java.lang.Double(v)) }.asJava
}
}

Related

How to ensure Scala generic function outputs a primitive array instead of an object array?

In my project I'm working with various handlers to perform logic on arrays of different primitive types, and I came across this runtime error:
[error] java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [B ([Ljava.lang.Object; and [B are in module java.base of loader 'bootstrap')
In this case I was working with Bytes, hence the [B, but one of my functions returned [Ljava.lang.Object instead (at runtime!). How can I ensure my generic functions return primitive arrays instead of object arrays?
Here's a minimal example to reproduce it:
package asdf
import scala.reflect.ClassTag
import java.nio.charset.StandardCharsets
object Main {
trait Helper[A, B] {
def decode(bytes: Array[Byte]): Array[A]
def aggregate(values: Array[A]): B
}
object StringHelper extends Helper[Byte, String] {
def decode(bytes: Array[Byte]): Array[Byte] = bytes.filter(_ != 0)
def aggregate(values: Array[Byte]): String = new String(values, StandardCharsets.UTF_8)
}
object IntHelper extends Helper[Int, Int] {
def decode(bytes: Array[Byte]): Array[Int] = bytes.map(_.toInt)
def aggregate(values: Array[Int]): Int = values.sum
}
def decodeAgg[A, B](bytes: Array[Byte], helper: Helper[A, B])(implicit ev: ClassTag[A]): B = {
val decoded = helper.decode(bytes)
val notFirstDecoded = decoded
.zipWithIndex
.filter({case (_, i) => i != 0})
.map(_._1)
.toArray
helper.aggregate(notFirstDecoded)
}
def main(args: Array[String]) {
val helper: Helper[_, _] = args(1) match {
case "int" => IntHelper
case "string" => StringHelper
case _ => throw new Exception("unknown data type")
}
val bytes = Array(97, 98, 99).map(_.toByte)
val aggregated = decodeAgg(bytes, helper)
println(s"aggregated to $aggregated")
}
}
Run with sbt "run -- string".
Full stack trace on this example:
[error] java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [B ([Ljava.lang.Object; and [B are in module java.base of loader 'bootstrap')
[error] at asdf.Main$StringHelper$.aggregate(Main.scala:12)
[error] at asdf.Main$.decodeAgg(Main.scala:29)
[error] at asdf.Main$.main(Main.scala:39)
I was using Scala 2.12, JDK 13.
I've tried using #specialized to no effect.
The problem lies in your toArray in call:
val notFirstDecoded = decoded
.zipWithIndex
.filter({case (_, i) => i != 0})
.map(_._1)
.toArray
toArray takes implicit ClassTag argument - it needs to know the runtime type of array elements to create the Array.
As you provide implicit ClassTag argument to decodeAgg, toArray happily takes what you deliver.
def decodeAgg[A, B](bytes: Array[Byte], helper: Helper[A, B])(implicit ev: ClassTag[A]): B
You can see that ClassTag corresponds to first generic argument of Helper.
You pass following helper:
val helper: Helper[_, _] = args(1) match {
case "int" => IntHelper
case "string" => StringHelper
case _ => throw new Exception("unknown data type")
}
The ClassTag is thus inferred to Object, which is why you get an Array of objects.
Note that if you use an IntHelper directly, the ClassTag is constrained to the correct type, and the function works as expected.
val aggregated = decodeAgg(bytes, IntHelper)
Solution ideas
There might be multiple ways to resolve it.
One idea might be to provide the classTag explicitly via Helper
import scala.reflect.ClassTag
import java.nio.charset.StandardCharsets
object Main {
trait Helper[A, B] {
def decode(bytes: Array[Byte]): Array[A]
def aggregate(values: Array[A]): B
def classTag: ClassTag[A]
}
object StringHelper extends Helper[Byte, String] {
def decode(bytes: Array[Byte]): Array[Byte] = bytes.filter(_ != 0)
def aggregate(values: Array[Byte]): String = new String(values, StandardCharsets.UTF_8)
def classTag: ClassTag[Byte] = ClassTag(classOf[Byte])
}
object IntHelper extends Helper[Int, Int] {
def decode(bytes: Array[Byte]): Array[Int] = bytes.map(_.toInt)
def aggregate(values: Array[Int]): Int = values.sum
def classTag: ClassTag[Int] = ClassTag(classOf[Int])
}
def decodeAgg[A, B](bytes: Array[Byte], helper: Helper[A, B]): B = {
val decoded = helper.decode(bytes)
val notFirstDecoded = decoded
.zipWithIndex
.filter({case (_, i) => i != 0})
.map(_._1)
.toArray(helper.classTag)
helper.aggregate(notFirstDecoded)
}
def main(args: Array[String]) {
val helper = args(1) match {
case "int" => IntHelper
case "string" => StringHelper
case _ => throw new Exception("unknown data type")
}
val bytes = Array(97, 98, 99).map(_.toByte)
val aggregated = decodeAgg(bytes, helper)
println(s"aggregated to $aggregated")
}
}

scala 2.13 auto implicit resolution error

I am facing this weird problem related to scala implicit resolution
Here is the code snippet
import scala.collection.Factory
import scala.collection.immutable.Seq
sealed trait A
sealed trait B
case class BImpl() extends B
case class AImpl() extends A
object implicitsContainer {
type AB = (A, B)
implicit def toStringAnyTuples[C[X] <: Iterable[X], A <: AB]
(col: C[A])
(implicit factory: Factory[(String, Any), C[(String, Any)]])
: C[(String, Any)] = {
factory.fromSpecific(col.iterator.map(f => f._1.toString -> f._2))
}
}
object Main extends App {
import implicitsContainer._
def a(f: Seq[(String, Any)]): Seq[(String, Any)] = f
val w: Seq[(AImpl, BImpl)] = Seq(AImpl() -> BImpl())
val x: Seq[(String, Any)] = a(w)
// Won't compile
// val y: Seq[(String, Any)] = a(Seq(AImpl() -> BImpl()))
}
Scala automatically picking up the implicit method
implicit def toStringAnyTuples[C[X] <: Iterable[X], A <: AB](col: C[A])
(implicit factory: Factory[(String, Any), C[(String, Any)]])
: C[(String, Any)] = {
factory.fromSpecific(col.iterator.map(f => f._1.toString -> f._2))
}
for this: -
val w: Seq[(AImpl, BImpl)] = Seq(AImpl() -> BImpl())
val x: Seq[(String, Any)] = a(w)
but throws an error for this
val y: Seq[(String, Any)] = a(Seq(AImpl() -> BImpl()))
and the error is:-
Error:(44, 47) type mismatch;
found : (AImpl, BImpl)
required: (String, Any)
val y: Seq[(String, Any)] = a(Seq(AImpl() -> BImpl()))
and one more point, if I remove the type from w
val w = Seq(AImpl() -> BImpl())
val x: Seq[(String, Any)] = a(w)
then also this will work fine.
The only error is with
val y: Seq[(String, Any)] = a(Seq(AImpl() -> BImpl()))
I am using: -
SCALA -> 2.13.3
SBT -> 1.3.13
JAVA -> 14
It's just type inference issue. Type parameter of Seq.apply was not inferred. Try
val y: Seq[(String, Any)] = a(Seq[(AImpl, BImpl)](AImpl() -> BImpl()))
or
val y: Seq[(String, Any)] = a(Seq[(A, B)](AImpl() -> BImpl()))
What you are experiencing is a symptom of the way inference works in the Scala compiler.
Here is a smaller example that shows the same issue:
object Test {
class C[T](x: T)
implicit def conv(c: C[Int]): C[String] = ???
def m(cs: C[String]) = 1
val ci = new C(1)
def t1: Int = m(ci) // OK
def t2: Int = m(new C(1)) // found: Int, expected: String
}
When type-checking new C(1), the compiler pushes down the expected type String to type
checking the expression 1, which fails. In the line above, type checking ci with expected type
C[String] succeeds thanks to the implicit conversion.
My suggestion here would be to define an extension method that performs the conversion, instead
of making the conversion implicit. This is also recommended for clarity - implicit conversions like
the one defined in your example can lead to surprising, hard to diagnose issues.
In my example, it would look like this:
object Test {
class C[T](x: T)
implicit class CExt(private val c: C[Int]) extends AnyVal {
def toCString: C[String] = ???
}
def m(cs: C[String]) = 1
val ci = new C(1)
def t1: Int = m(ci.toCString)
def t2: Int = m(new C(1).toCString)
}

Scala Typeclass for methods with parameters

I have tried to add methods like "multiply by a scalar" to Array[T] via a typeclass, to mimic numpy functionality. I have looked at an example, which works and adds a "show" method with no parameters to Array[T]. However, in my case, I find that I am unable to add methods with parameters, e.g. array.*(2.0).
Using Scala 2.12.6.
How can I make this code work?
package numpy
trait BehaveLikeNumpy[T] {
def *(a: Array[T], x: T): Array[T]
}
object BehaveLikeNumpyInstances {
def apply[T](implicit bln: BehaveLikeNumpy[T]): BehaveLikeNumpy[T] = bln
object ops {
def *[T: BehaveLikeNumpy](a: Array[T], x: T): Array[T] = BehaveLikeNumpyInstances[T].*(a, x)
implicit class BehaveLikeNumpyOps[T: BehaveLikeNumpy](a: Array[T]) {
def *(x: T) = BehaveLikeNumpyInstances[T].*(a, x)
}
}
implicit val arrayTimes_Double = (a: Array[Double], x: Double) => a.map(y => y * x)
}
package some.pkg
import numpy.BehaveLikeNumpyInstances
import numpy.BehaveLikeNumpyInstances.ops._
val aaa: Array[Double] = (0 until 5).toArray.map(_.toDouble)
aaa.show // Works. See https://blog.scalac.io/2017/04/19/typeclasses-in-scala.html
val s1 = aaa.*(2.0)// Error: value * is not a member of Array[Double]
val s2 = aaa * 2.0 // Error: value * is not a member of Array[Double]
Firstly you lost type (for transformation of lambda to SAM trait)
implicit val arrayTimes_Double: BehaveLikeNumpy[Double] =
(a: Array[Double], x: Double) => a.map(y => y * x)
secondly you lost underscore
import numpy.BehaveLikeNumpyInstances._

How to use ConcurrentHashMap computeIfAbsent() in Scala

I'm using a ConcurrentHashMap in Scala and I would like to use the computeIfAbsent() method but can't figure out the syntax for the second argument. Can someone show me what would be the proper syntax?
When running the following code
val data = new ConcurrentHashMap[String, LongAdder]
data.computeIfAbsent("bob", k: String => new LongAdder()).increment()
I'm getting the following error
Type mismatch, expected: Function[_ >: String, _ <: LongAdder], actual: (String) => Any
Thanking you in advance
Francis
The problem is that you're using java.util.concurrent.ConcurrentHashMap, which accepts java.util.function.Function as a parameter for computeIfAbsent() instead of scala.Function1 which you pass to it.
Since scala doesn't support lambda conversion for functional interfaces as Java does (at least not without the -Xexperimental flag), you can solve this by implementing a java.util.function.Function explicitly:
val data = new ConcurrentHashMap[String, LongAdder]
val adderSupplier = new java.util.function.Function[String, LongAdder]() {
override def apply(t: String): LongAdder = new LongAdder()
}
data.computeIfAbsent("bob", adderSupplier).increment()
Alternatively, if you need this more often, you may write a utility conversion function or even an implicit conversion:
object FunctionConverter {
implicit def scalaFunctionToJava[From, To](function: (From) => To): java.util.function.Function[From, To] = {
new java.util.function.Function[From, To] {
override def apply(input: From): To = function(input)
}
}
}
import FunctionConverter._
val data = new ConcurrentHashMap[String, LongAdder]()
data.computeIfAbsent("bob", (k: String) => new LongAdder()) // <- implicit conversion applied here
If you enable -Xexperimental flag you can use scala anonymous function notation for this:
scala> val data = new java.util.concurrent.ConcurrentHashMap[String, Int]
data: java.util.concurrent.ConcurrentHashMap[String,Int] = {}
scala> data.computeIfAbsent("bob", _.size)
res0: Int = 3
Note that you still can't pass regular scala Function
scala> val f: String => Int = _.size
f: String => Int = <function1>
scala> data.computeIfAbsent("bob", f)
<console>:13: error: type mismatch;
found : String => Int
required: java.util.function.Function[_ >: String, _ <: Int]
data.computeIfAbsent("bob", f)
^
But eta-expansion will work
scala> def a(s: String): Int = s.size
a: (s: String)Int
scala> data.computeIfAbsent("bob", a)
res3: Int = 3

Map tuple to tuple in Scala

I want to map a pair of options of String like the following
val pair: (Option[String], Option[String]) = (Some("a"), None)
val mapped: (String, String) = pair map {case (a:Option[String],b:Option[String]) => (a.getOrElse(""),b.getOrElse(""))}
but the output signature is different from what I expected
(Option[String],(String,String))
It seems that I'm missing something here... maybe scalaz or shapeless allows for such functionality of mapping tuples?
Simple change from map to match you'll get expected types.
scala> val pair: (Option[String], Option[String]) = (Some("a"), None)
pair: (Option[String], Option[String]) = (Some(a),None)
scala>
scala> val mapped: (String, String) = pair match {case (a:Option[String],b:Option[String]) => (a.getOrElse(""),b.getOrElse(""))}
mapped: (String, String) = (a,"")
scala>
scala> mapped
res8: (String, String) = (a,"")
In case if you specifically want to do things like that with shapeless, you should make some preparations.
First tell your compiler what you want to use in case of None:
class Default[T](val value: T)
implicit object defaultString extends Default[String]("")
Now create your function to map:
import shapeless._
object extract extends Poly1 {
implicit def withDefault[T](implicit default: Default[T]) =
at[Option[T]](_ getOrElse default.value)
}
Now use shapeless extension for tuples:
import syntax.std.tuple._
pair.map(extract) // res0: (String, String) = (a,)