3

What do methods mkNumericOps andmkOrderingOps of scala.math.Integral do and how can we use them?

I understand that functions and object methods can be declared implicit and used for implicit conversion. However I do not understand why traits methods are declared implicit.

BTW, can class methods be declared implicit too?

Michael
  • 10,185
  • 12
  • 59
  • 110
  • What do you mean by _trait methods_ and _class methods_? All methods are defined on a class or a trait, though some are defined on anonymous subclasses that in a seemless manner. – Daniel C. Sobral Mar 31 '11 at 22:19

1 Answers1

8

First, let's see their declaration:

implicit def mkNumericOps (lhs: T): IntegralOps
implicit def mkOrderingOps (lhs: T): Ops

The fact that they are implicit means their goal is to provide some automatic value or conversion. Note that they both convert from T to some other type, where T is the type parameter of the trait: Integral[T].

So, if you have Integral[Int], then mkNumericOps will give you an automatic conversion from Int to IntegralOps. That means you'll be able to call methods from IntegralOps or Ops on an Int (or whatever it is the type of your Integral).

Now, let's see what methods are these:

def % (rhs: T): T
def * (rhs: T): T
def + (rhs: T): T
def - (rhs: T): T
def / (rhs: T): T
def /% (rhs: T): (T, T)
def abs (): T
def signum (): Int
def toDouble (): Double
def toFloat (): Float
def toInt (): Int
def toLong (): Long
def unary_- (): T

These are from IntegralOps, which extends Ops. An interesting thing about them is that many of them are already defined on Int! So, how and why one would use them? Here's an example:

def sum[T](list: List[T])(implicit integral: Integral[T]): T = {
    import integral._   // get the implicits in question into scope
    list.foldLeft(integral.zero)(_ + _)
}

So, given any type T for which there's an Integral[T] implicitly available, you can pass a list of that type to sum.

If, on the other hand, I made my method specific for the type Int, I could write it without Integral. On the other hand, I can't write something that will work for both Int and Long and BigInt, because they do not share a common ancestor defining the method + (much less a `zero´).

The foldLeft above is effectively translated as this:

list.foldLeft(integral.zero)((x, y) => mkNumericOps(x).+(y))
Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681