Salim Fadhley
Salim Fadhley

Reputation: 8235

Constraining types in Scala's generics to accept any kind of Int

I want to write a function vaguely like:

def doubleit[A](a: A): A = {a + a}

But I want 'A' to mean any kind of Int, but not anything. Is there a way to give Scala a clue about what I want 'A' to mean?

def doubleit[A <: Int](a: A): A = {a + a}

is rejected by the compiler.

Upvotes: 1

Views: 189

Answers (1)

Kolmar
Kolmar

Reputation: 14224

In plain Scala you can use type class Integral:

scala> def doubleit[A : Integral](a: A): A = implicitly[Integral[A]].plus(a, a)
doubleit: [A](a: A)(implicit evidence$1: Integral[A])A

scala> doubleit(2)
res0: Int = 4

scala> doubleit(BigInt(4))
res1: scala.math.BigInt = 8

Another possible syntax:

def doubleit[A](a: A)(implicit ev: Integral[A]): A = ev.plus(a, a)

ev is a commonly used name for those implicit parameters.

It is also possible to use normal operations like +, -, etc. instead of plus and minus:

def doubleit[A](a: A)(implicit ev: Integral[A]): A = {
  import ev._
  a + a
}

Or as per suggestion by @KChaloux, import from Integral.Implicits beforehand:

import Integral.Implicits._
def doubleit[A : Integral](a: A): A = a + a

If you want the function to support not only integers, but also Doubles, BigDecimals, etc. you can use Numeric instead of Integral:

import Numeric.Implcits._
def doubleit[A : Numeric](a: A): A = a + a

Explanation:

Writing [A : Integral] makes the function receive an implicit parameter of type Integral[A]. The implicits for all basic integral types are already defined in Scala, so you can use it with Int or BigInt straightaway. It is also possible to define new Integral types by defining a new implicit variable of type Integral[NewIntegralType] and implementing all the necessary methods.

The call to implicitly[Integral[A]] returns this implicit instance of Integral[A] which has method plus for addition, and other methods for performing other operations on integrals.

Upvotes: 6

Related Questions