Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstracting over Float, Double, and BigDecimal in Scala

Tags:

scala

I had suspected there would be support for this already built into Scala's type system, but after wading through Numeric and Fractional and FractionalProxy, I wasn't able to figure out a way.

I want to define a numerical model abstractly, such that it can work with Doubles, Floats, and BigDecimals, with specializations for Float and Double.

I seem to have made it work, but with a lot of effort and boilerplate. First, is there (please?) a less kludgey, more concise way? Second, will my use of value types be effective at keeping the specialized-to-primitive types from getting wrapped, despite the implicit conversions of the view bounds?

Many thanks.

object Model {

  sealed trait Value[T] extends Any { //contains all the operations I use
    def value : T;
    def + ( other : Value[T]) : Value[T];
    def / ( other : Value[T]) : Value[T];
    def - ( other : Value[T]) : Value[T];
    def * ( other : Value[T]) : Value[T];
    def < ( other : Value[T]) : Boolean;

    def unary_- : Value[T];
    def abs : Value[T];
  }

  implicit def unwrap[T]( wrapped : Value[T]) : T = wrapped.value;

  implicit class FloatValue( val value : Float ) extends AnyVal with Value[Float] {
    def + ( other : Value[Float]) : Value[Float] = new FloatValue(value + other.value)
    def / ( other : Value[Float]) : Value[Float] = new FloatValue(value / other.value)
    def - ( other : Value[Float]) : Value[Float] = new FloatValue(value - other.value)
    def * ( other : Value[Float]) : Value[Float] = new FloatValue(value * other.value)
    def < ( other : Value[Float]) : Boolean = value < other.value;

    def unary_- : Value[Float] = new FloatValue( -value );
    def abs : Value[Float] = new FloatValue( math.abs( value ) );
  }

  implicit class DoubleValue( val value : Double ) extends AnyVal with Value[Double] {
    // body of FloatValue repeated, but with Double replacing Float
  }

  implicit class BigDecimalValue( val value : BigDecimal ) extends AnyVal with Value[BigDecimal] {
    // body of FloatValue repeated, but with BigDecimal replacing Float
  }
}

class GrossInterestModel[@specialized(Double,Float) T <% Value[T]]( zero : T ) {
   def runModel( a : T, b : T ) : T = {
      //do math here, using the operations defined in Value above
   }
}
like image 989
Steve Waldman Avatar asked May 11 '13 01:05

Steve Waldman


1 Answers

Scala built-in collection already implemented similar things in Numeric.scala. You can use them directly. Some thing like (from TraversableOnce.scala):

def sum[B >: A](implicit num: Numeric[B]): B = foldLeft(num.zero)(num.plus)
like image 81
Max Avatar answered Nov 15 '22 07:11

Max