questionersam
questionersam

Reputation: 1125

Scala Numeric init with constant 0

Lets I have a utility class called MathUtil.

and it looks like this .

abstract class MathUtil(T:Numeric){
   def nextNumber(value:T)
   def result():T
}

Lets I subclass it this way

class SumUtil[T:Numeric] extends MathUtil[T]{
   private var sum:T = 0
   override def nextNumber(value:T){
     sum = sum + value
   }
   override def result():T = sum
}

I have a problem with the statement

private var sum:T = 0

Now , I have to initialize to sum to 0. I would guess any numeric to have a way to represent 0. Im pretty new to scala. How do I solve this issue ?

Upvotes: 7

Views: 1345

Answers (2)

Ben Kyrlach
Ben Kyrlach

Reputation: 379

I think that there needs to be a little clarification of exactly what you're trying to accomplish. From the Scala docs, the Numeric type itself is generic. My feeling here is what you actually want is to describe a MathUtil abstraction that handles any Numeric[T] rather than subclasses of Numeric[_] which is what your code is currently describing. Here is the correct implementation based on that assumption.

//Define a MathUtil that works on any T
abstract class MathUtil[T] {
    def nextNumber(value: T)
    def result(): T
}

//Define a SumUtil that works on any T that has an available Numeric
//Will search implicit scope, but also allows you to provide an
//implementation if desired.
class SumUtil[T](implicit n: Numeric[T]) extends MathUtil[T] {
    //Use the Numeric to generate the zero correctly.
    private var sum: T = n.zero
    //Use the Numeric to correctly add the sum and value
    override def nextNumber(value: T) = sum = n.plus(sum, value)
    override def result(): T = sum
}

//Test that it works.
val a = new SumUtil[Int]
val b = List(1,2,3)

b map a.nextNumber //Quick and dirty test... returns a meaningless list
println(a.result)  //Does indeed print 6

If the above doesn't do what you want, please clarify your question.

Upvotes: 0

Travis Brown
Travis Brown

Reputation: 139048

The Numeric type class instance has a zero method that does what you want:

class SumUtil[T: Numeric] extends MathUtil[T] {
   private var sum: T = implicitly[Numeric[T]].zero
   override def nextNumber(value: T) {
     sum = implicitly[Numeric[T]].plus(sum, value)
   }
   override def result(): T = sum
}

Note that you also need the instance for the plus method, unless you import Numeric.Implicits._, in which case you can use +. You can also clean the code up a bit by not using the context bound syntax in this case:

class SumUtil[T](implicit ev: Numeric[T]) extends MathUtil[T] {
   import Numeric.Implicits._
   private var sum: T = ev.zero
   override def nextNumber(value: T) {
     sum = sum + value
   }
   override def result(): T = sum
}

This is exactly equivalent: the context bound version is just syntactic sugar for this implicit argument, but if you need to use that argument explicitly (as you do here, for its zero), I find it cleaner to write the desugared version.

Upvotes: 12

Related Questions