I am playing around with implicits a bit (I'm learning Scala currently) and wrote a simple class to represent temperatures, with scale conversions. This uses a 'TempOps' class to provide implicit operations on numerics so I can write things like:
(5 Celsius) asFahrenheight
Because I want it to work for any numeric type (at least the built-in ones) I abstracted the TempOps class using an implicit Numeric type class. The code is as follows:
package exercises.temperature
/**
* Created by steve on 9/16/2015.
*/
sealed case class Temperature(kelvin: Double) {
import Temperature._
override def toString():String = s"$kelvin Kelvin"
def asKelvin = kelvin
def asFahrenheight = ctof(ktoc(kelvin))
def asCelsius = ktoc(kelvin)
def asK = asKelvin
def asF = asFahrenheight
def asC = asCelsius
}
sealed case class TempOps[N](t: N)(implicit n: Numeric[N]) {
implicit val Fahrenheit = Temperature.Fahrenheit(n.toDouble(t))
implicit val Celsius = Temperature.Celsius(n.toDouble(t))
implicit val Kelvin = Temperature(n.toDouble(t))
}
object Temperature {
private val absoluteZeroC = -273.15
private def ftoc(f: Double) = (f-32)*5/9
private def ctok(c: Double) = c - absoluteZeroC
private[temperature] def ktoc(k: Double) = k + absoluteZeroC
private[temperature] def ctof(c: Double) = c*9/5 + 32
private[temperature] def Fahrenheit(f: Double) = Temperature(ctok(ftoc(f)))
private[temperature] def Celsius(c: Double) = Temperature(ctok(c))
implicit def toTempOps(n: Int) = TempOps(n)
}
This works, but suppose I want to preserve the original numeric type so that in the following the result is still an Int rather than a Double (up to some rounding obviously):
val originalTempValue: Int = 5 // Explicitly an Int
val converted = (originalTempValue Celsius) asFahrenheit
'converted' will now be a Double. How can I modify TempOps to 'preserve' the numeric type being implicitly used, so that in the above 'converted' would wind up being an Int?