The Rational class is a fine example of a useful utility class.
Still, to an experienced user, it has a striking deficiency:
A Rational is a *number* and we are used to doing arithmetic with
standard operators. We would like to replace the mouthful
`frac1.Multiply(frac2)`

by our common symbolism for multiplication,
`frac1*frac2`

. This can be coded in C#, using *operator overloading* to
give new meanings to the operator `*`

. The C# syntax is illustrated in the
variant of the Rational class in
rational_ops_stub/rational.cs. This class also contains code
discussed in the
next section, Casts in User-Defined Classes.
Here are operator overload declarations for `*`

and others:

```
/// * binary multiplication operator
public static Rational operator *(Rational f1, Rational f2)
{
return new Rational(f1.num*f2.num, f1.denom*f2.denom);
}
/// - unary negation operator
public static Rational operator - (Rational r)
{
return new Rational(-r.num, r.denom);
}
/// binary == operator
public static Boolean operator ==(Rational f1, Rational f2)
{
return f1.num == f2.num && f1.denom == f2.denom;
}
/// binary != operator
public static Boolean operator !=(Rational f1, Rational f2)
{
return f1.num != f2.num || f1.denom != f2.denom;
} // or extra call, but clearly consistent: return !(f1 == f2)
```

All operator overload headings have the special form

`public static`

returnType`operator`

opSymbol`(`

parameters`)`

Here opSymbol can be any arithmetic or comparison operator, or
some other operators that we have not discussed. So something like
`operator *`

or `operator -`

replaces the method name.
Binary operations like multiplication require two operands, and hence the
method has two parameters.
The method
computes and returns the named return type in the normal fashion.
In general
at least one of the parameters must be of the type of the class being defined.

(We could have directly defined four further overloads of `*`

,
with the first or second parameter
being an `int`

or a `double`

, but we will avoid that by also adding methods
to provide implicit Casts in User-Defined Classes.)

The `-`

symbol is special, since it can be used either as a unary operator for
negation, or as a binary operator for subtraction. Since we include only
one parameter above, we are defining the unary version.

The operator does not need to produce a result of the same type. We
included `==`

and `!=`

as examples (returning a `Boolean`

).

(These methods
do not cause compiler errors, but warnings are generated:
We have not added further more advanced
overrides of Equals and HashCode methods, that are ideally in sync with
the meaning of `==`

. You should see a discussion of these methods in a
data structures course, like Loyola’s Comp 271.)

The class is a stub, and Operator Overloading Exercise invites you to add further operator overloads.

**Precedence**: Note that the operator overloading method definitions include
nothing about Precedence of Operators. That is because the precedence of operators
is fixed across the whole language. Unary `-`

has higher
precedence than `*`

... no matter what the types involved.

An example testing class also uses the new casting syntax of next section:

We have discussed casts before. We know that an `int`

can also be represented
as a `double`

with an integer value, and the cast from `int`

to `double`

is done implicitly
when needed: An expression like `3.2 * 2`

is processed by the compiler,
*implicitly* casting the
2 to `double`

2.0, and then doing a `double`

multiplication.
The same idea makes sense with an
`int`

`n`

and a Rational `f`

. We only defined the operator overload `*`

for two Rationals, so in our code so far, `f * n`

does not make sense.
Mathematically an integer is rational, so mathematically, it should make sense.
We bridge this difference by defining an implicit cast of an `int`

to a Rational,
so the compiler will take `f * n`

and see the need to implicitly cast
`n`

to a Rational. The definition below will also allow explicit casts
if you choose, like `f * (Rational) n`

:

```
/// Code to cast an int to a Rational implicitly when needed.
public static implicit operator Rational(int n)
{
return new Rational(n, 1);
}
```

Again it is
the heading that takes a special form, starting with
`public static implicit operator`

followed by the type being cast to,
like Rational, while the parameter is the starting type, like `int`

.
This is not like a regular method with its return type and method name.
Here it looks something like a constructor with a type in place of a method
name, but a constructor would not start with `static implicit operator`

!

Now consider a `double`

`d`

and a Rational `f`

.
We would like to allow an expression like
`d * f`

.
Again, the operator overload for `*`

does not allow this directly, so consider
implicit casts: Since
a `double`

is only an approximation, in general,
it would not be wise to implicitly convert
a `double`

to a Rational, but it does make sense to approximate a Rational
by a `double`

before use with a `double`

:

```
/// Code to cast to a double implicitly when needed.
public static implicit operator double(Rational f)
{
return (double)f.num/f.denom;
}
```

The general format of such an implicit cast in a user-defined class is:

`public static implicit operator`

resultType`(`

sourceTypeparamName`)`

One of the two types should be the type of the containing class. We have illustrated both combinations.

Finally, you need to be *very careful where you declare implicit casts*, to
make sure you are not being overly general, and maybe allowing
trouble in a form that may be very hard to debug:
It is much harder to foresee and trace implicit actions than explicit actions.
You are
*safe*, but more *verbose*, if you *only allow explicit* casts. For example,
we have already seen these required for a cast from `double`

to `int`

.
To only allow an explicit cast with your type,
replace `implicit`

by `explicit`

in the cast method heading.

```
/// Code to cast to a decimal with an explicit cast.
public static explicit operator decimal(Rational f)
{
return (decimal)f.num/f.denom;
}
```

**The decimal type**: Though we have not used the
`decimal`

type before, we use it here for contrast to illustrate a cast
from Rational to `decimal`

that can only be used explicitly, as in
`(decimal) f`

:

Example rational_ops_stub/test_ops.cs tests all of the operator overloads and casts shown for a Rational. Look at the source code and run it. Note where overloaded operators are used and where implicit and explicit casts to or from a Rational are used.

The example also illustrates a special feature
of the `decimal`

type. While a `double`

is encoded with a power of 2, so
0.1 is *not* stored accurately, a `decimal`

is encoded with a power of 10, so
exact decimal values with up to 28 digits can be stored and manipulated.
(This is important for *monetary calculations*, so a `decimal`

literal
has **m** for money appended, like `5.99m`

, representing the mathematical
quantity 5.99 *exactly*.)

The classes discussed above from example project rational_ops_stub are incomplete. Add the overloaded binary operators /, +, -, <, >, <= and >= to the Rational class, and extend the TestOps class to test them.