user6247850 user6247850 - 1 month ago 8
Scala Question

Scala type conversions in polymorphic method

I'm fairly new to Scala after working with Java for a while, so I apologize if this is a basic question. I have a method that I would like to be run in either float or double precision, and it seemed like it would be fairly easy to do with Scala's polymorphism. In Java, the only way I found to do it was by overloading the method and having one take float arguments and the other take double arguments, but I'm hoping that polymorphism would allow me to avoid that and just have one method that will work with either. The way I've implemented it so far looks like this (http://stackoverflow.com/a/4033390/6247850 for how to make the generic operations work between arguments):

def Sample[A: Numeric](x: A, y: A)(implicit num: Numeric[A]): A= {
import num._
var out = 2.0.asInstanceOf[A] * x * y
return out
}


This works fine for double precision, but results in a ClassCastException if I try to run it in Float. I can hardcode a workaround by changing it to
2.0.toFloat.asInstanceOf[A]
which makes me think there has to be some way to do this, but hardcoding like that defeats the point of making it generic. I also had to do what seemed like a disproportionate amount of work to get division to work properly by using this answer http://stackoverflow.com/a/34977463/6247850, and building off of it to get a less than comparison to work.

Essentially, what I want is the ability to specify the precision that a method should run in and return. The problem comes from casting other variables used in the method to the appropriate type since
.asInstanceOf[A]
doesn't work unless it already was the correct type.

Answer

Here's a short solution using methods from Numeric explicitly:

def Sample[A: Numeric](x: A, y: A)(implicit num: Numeric[A]): A = {
  num.times(
    num.fromInt(2),
    num.times(x, y)
  )
}

This allows first to resolve any ambiguities with the overloaded arithmetic operators. The actual key here was the usage of the fromInt method, so we can write it shorter (just as in your code) with operators again:

def Sample[A: Numeric](x: A, y: A)(implicit num: Numeric[A]): A = {
  import num._
  fromInt(2) * x * y
}

You don't need any casting here (in this particular example). Here's a usage demo:

scala> Sample(2.5D, 0.01D)
res12: Double = 0.05

scala> Sample(2.5F, 0.01F)
res13: Float = 0.049999997

Regarding more general situation when just have some number instead of 2 and you don't know which type you want it to be in advance, I think, you can't solve it with just one polymorphic function. You can define a typeclass and provide implicit instances for particular types you want it to work with (ad-hoc polymorphism).