# Odersky's book, Chapter 6, Rational questions

In Programming in Scala there is an example Rational class which begins

class Rational(n: Int, d: Int) {
require(d != 0)
private val g = gcd(n.abs, d.abs)
val numer = n / g
val denom = d / g

I just want to verify that g sticks around for the life of the object so that 3 values are stored instead of just 2. If space was more important than time, this would be more efficient:

class Rational(n: Int, d: Int) {
require(d != 0)
val numer = n / gcd(n.abs, d.abs)
val denom = d / gcd(n.abs, d.abs)

Also, this class works with Int, but what if I want to use Long? I can have a RationalInt class and a RationalLong class, but 99% of the code is duplicated. It seems like a templated Rational[T] would be effective, but not just any T has an abs function (among others). I can’t figure out how to use Integral or anything like it in the template. Can someone show a way to have

class Rational[?] { }
class RationalInt extends Rational[Int] { }
class RationalLong extends Rational[Long] { }

or something like that? Thanks.

In Programming in Scala there is an example Rational class which
begins

class Rational(n: Int, d: Int) {
require(d != 0)
private val g = gcd(n.abs, d.abs)
val numer = n / g
val denom = d / g

I just want to verify that g sticks around for the life of the
object so
that 3 values are stored instead of just 2. If space was more
important
than time, this would be more efficient:

That’s correct, `g` would occupy the space of one `Int`.
You could also write

``````class Rational(n: Int, d: Int) {
require(d != 0)
val (numer, denom) = {
val g = gcd(n.abs, d.abs)
(n/g, g/d)
}
}
``````

although it might perform slightly worse due to the temporary
construction of a tuple. Or use a companion object

``````object Rational {
def apply(n: Int, d: Int): Rational = {
require(d != 0)
val g = gcd(n.abs, d.abs)
new Rational(n/g, g/d)
}
}
class Rational private(val numer: Int, val denom: Int)
``````

Probably this would be the best form.

It seems like a templated Rational[T] would be effective,
but not just any T has an abs function (among others). I can’t figure
out how to use Integral or anything like it in the template. Can someone
show a way to have

There are so-called type classes for numeric operations: Numeric
modulus). You need Integral because gcd requires modulus.

There are default instances for Int, Long and others

``````implicitly[Integral[Long]] // -> scala.math.Numeric.LongIsIntegral
``````

These have the necessary math operations, e.g.

``````scala.math.Numeric.LongIsIntegral.rem(10L, 6L)  // 4
``````

If you import the members of such an instance of Integral, you can use
’operators’ almost as before (because it provides extension methods
through `mkNumericOps`). So instead of

``````def gcd[A](a: A, b: A)(implicit num: Integral[A]): A = {
if (b == num.zero) a else gcd(b, num.rem(a, b))
}
``````

you can write

``````def gcd[A](a: A, b: A)(implicit num: Integral[A]): A = {
import num._
if (b == zero) a else gcd(b, a % b)
}
``````

Then the whole class could be written

``````object Rational {
def apply[A](n: A, d: A)(implicit num: Integral[A]): Rational[A] = {
import num._
require (d != zero)
val g = gcd(n.abs, d.abs)
new Rational(n / g, d / g)
}

private def gcd[A](a: A, b: A)(implicit num: Integral[A]): A = {
import num._
if (b == zero) a else gcd(b, a % b)
}
}
class Rational[A] private (val numer: A, val denom: A)(implicit num:
Integral[A]) {
import num._

override def toString = s"\$numer/\$denom"

def + (that: Rational[A]): Rational[A] =
Rational(numer * that.denom + that.numer * denom,
denom * that.denom)
}
``````

Test:

``````Rational(4L, 8L) + Rational(5L, 9L)  // 19/18
``````

best, .h.h.

That’s awesome! I thought of the tuple method as well, but your solution with the companion object is much better. Although I knew about Integral, how to use it was a mystery. (implicit num: Integral[A]) must be further along in the book. Thanks!