1) I think gcd shouldn't be part of Rational, because they are completely independent mathematical ideas. In the current* way, I feel, the book encourages that we implement what we need in the classes where we need them. In the practice this would lead to a) confused classes and b) many independent implementations of the same functionalities...
*: Build date of my PDF is April 6, 2016
2) What bothers me more, that gcd does not give the right result for some pairs containing negative numbers and for the pair (0,0). E.g.:
scala> def gcd(a: Int, b: Int): Int = | if (b == 0) a else gcd(b, a % b) gcd: (a: Int, b: Int)Int
scala> gcd(3,-7) res2: Int = -1
scala> gcd(-2,-6) res3: Int = -2
scala> gcd(0,0) res2: Int = 0
Note: gcd must always be positive and has no meaning for (0,0).
This is not a problem in the current code as we require( d != 0) and call gcd with abs-s. However, I think gcd should not rely on its callers to get always fine parameters and should always give back good results.
BTW gcdLoop (Listing 7.2 on PDF page 157) and gcd (Listing 7.4) suffer from the same problem: they calculate gcd correctly for positiv numbers, while give unreliable results for others.
I think it is a bad message if the book suggests that we do not have to write correct programs, "good enough" is good enough...
Looking more into it, I see that accoring to some definitions of gcd, gcd(0,0) is indeed 0 and both -3 and 3 can be seen as the gcd-s of (-3,-6)... However, such definitions are so uncommon that I can't find any of them on Internet... So virtually all definitions on Internet (Wikipedia, wolframalpha, matlab, various univerity papers, etc.) show, that the gcd and gcdLoop functions (all 3 in the book) are wrong.
I would suggest a clarification footnote, referring perhaps to a correct definition and/or fixing the functions to comply with the common definition.