Previous | Table of Contents | Next |
10.4.2.5. Implementing the Rationals and Rationals.IO Packages
Now examine the implementation of the Rationals package. In Ada, the implementation is called a package body, as line 1 shows.
1 package body HB.Rationals is 2 3 function / (X, Y : Integer) return Rational is 4 begin 5 if Y = 0 then 6 raise ZeroDenominator; 7 elsif X = 0 then 8 return (Numerator => 0, Denominator => 1); 9 elsif Y > 0 then 10 return (Numerator => X, Denominator => Y); 11 else 12 return (Numerator => -X, Denominator => -Y); 13 end if; 14 end /; 15 16 function Numer (R : Rational) return Integer is 17 begin 18 return R.Numerator; 19 end Numer; 20 21 function Denom (R : Rational) return Positive is 22 begin 23 return R.Denominator; 24 end Denom; 25 26 function = (R1, R2 : Rational) return Boolean is 27 begin 28 return Numer(R1)*Denom(R2) = Numer(R2)*Denom(R1); 29 end =; 30 31 function < (R1, R2 : Rational) return Boolean is 32 begin 33 return Numer(R1)*Denom(R2) < Numer(R2)*Denom(R1); 34 end <; 35 36 function > (R1, R2 : Rational) return Boolean is 37 begin 38 return Numer(R1)*Denom(R2) > Numer(R2)*Denom(R1); 39 end >; 40 41 function <= (R1, R2 : Rational) return Boolean is 42 begin 43 return Numer(R1)*Denom(R2) <= Numer(R2)*Denom(R1); 44 end <=; 45 46 function >= (R1, R2 : Rational) return Boolean is 47 begin 48 return Numer(R1)*Denom(R2) >= Numer(R2)*Denom(R1); 49 end >=; 50 51 function +(R : Rational) return Rational is 52 begin 53 return R; 54 end +; 55 56 function -(R : Rational) return Rational is 57 begin 58 return (-Numer(R)) / Denom(R); 59 end -; 60 61 function abs(R : Rational) return Rational is 62 begin 63 return (abs Numer(R)) / Denom(R); 64 end abs; 65 66 function +(R1, R2 : Rational) return Rational is 67 begin 68 return (Numerator => 69 Numer(R1)*Denom(R2) + Numer(R2)*Denom(R1), 70 Denominator => Denom(R1)*Denom(R2)); 71 end +; 72 73 function -(R1, R2 : Rational) return Rational is 74 begin 75 return (Numerator => 76 Numer(R1)*Denom(R2) - Numer(R2)*Denom(R1), 77 Denominator => Denom(R1)*Denom(R2)); 78 end -; 79 80 function *(R1, R2 : Rational) return Rational is 81 begin 82 return (Numerator => Numer(R1)*Numer(R2), 83 Denominator => Denom(R1)*Denom(R2)); 84 end *; 85 86 function /(R1, R2 : Rational) return Rational is 87 begin 88 return (Denominator => Numer(R1)*Numer(R2), 89 Numerator => Denom(R1)*Denom(R2)); 90 end /; 91 92 end HB.Rationals;
Lines 3-14 implement the / operator. This is simply a matter of checking the various cases. In the first case (line 6), an attempt to store 0 in the denominator, we
raise ZeroDenominator;
Because there is no exception handler in this function, the exception is propagated to the point where the client called the function. If the client provides a nearby handler, control is passed to it; otherwise, control passes to the next higher level in the call chain and so forth until either the exception is handled somewhere in the application or it passes beyond the main program to the runtime system.
It is quite common in Ada to declare exceptions in package interfaces and then raise them in package implementations. This sort of exception responds to a client programs violation of the abstraction provided by the packagein this case, the mathematical prohibition against 0 in the denominator of a rational number. The package cannot be expected to clean up a violation such as this: The client caused the problem and the client is responsible for solving it. Adas exception-propagation rules encourage programmers to design such that responsibility for anomalies and violations is passed to, and handled by, just the right layer of the overall program.
Previous | Table of Contents | Next |