Imagine you are calculating the age values in such as way that occasionally tests
are failing because of rounding differences that you actually don't care about. For example, you
expect an age of 29.0, but you're sometimes seeing 29.0001:

The === operator looks for an implicit Equality[L], where L is the left-hand type: in this
case, Person. Because you didn't specifically provide an implicit Equality[Person], === will fall back on
default equality, which will call Person's equals method. That equals method, provided by the Scala compiler
because Person is a case class, will declare these two objects unequal because 29.001 does not exactly equal 29.0.

To make the equality check more forgiving, you could define an implicit Equality[Person] that compares
the ageDoubles with a tolerance, like this:

Default equality

Scalactic defines a default Equality[T] for all types T whose areEqual method works by first
calling .deep on any passed array, then calling == on the left-hand object, passing in the right-hand object.
You can obtain a default equality via the default method of the Equality companion object,
or from the defaultEquality method defined in TripleEqualsSupport.

About equality and equivalence

The Equality trait represents the Java Platform's native notion of equality, as expressed in the signature and contract of
the equals method of java.lang.Object. Essentially, trait Equality enables you to write alternate
equals method implementations for a type outside its defining class.

In an equals method, the left-hand type is known to be the type of this, but
the right-hand type is Any.
As a result, you would normally perform a runtime type test to determine whether the right-hand object is of an appropriate type for equality,
and if so, compare it structurally for equality with the left-hand (this) object.
An an illustration, here's a possible equals
implementation for the Person case class shown in the earlier example:

The areEquals method of Equality[T] is similar. The left-hand type is known to be T, but the right-hand type is Any, so
normally you'd need to do a runtime type test in your areEqual implementation.
Here's the areEqual method implementation from the earlier Equality[Person] example:

Equality is used by TripleEquals, which enforces no type constraint between the left and right values, and the
equal, be, and contain syntax of ScalaTest Matchers.

By contrast, TypeCheckedTripleEquals
and ConversionCheckedTripleEquals use an Equivalence.
Equivalence differs from Equality in that both the left and right values are of the same type. Equivalence works for
TypeCheckedTripleEquals because the type constraint enforces that the left type is a subtype or supertype of (or the same type as) the right
type, and it widens the subtype to the supertype. So ultimately, both left and right sides are of the supertype type. Similarly, Equivalence
works for ConversionCheckedTripleEquals because the type constraint enforces that an implicit conversion
exists from either the left type to the right type, or the right type to the left type, and it always converts one
type to the other using the implicit conversion. (If both types are the same type, the identity implicit conversion
from Predef is used.) Because of the conversion, both left and right sides are ultimately of the
converted-to type. Here's an example of how writing an Equivalence's areEquivalent
method might look:

Scalactic provides both Equality and Equivalence because the Any in
Equality can sometimes make things painful. For example, in trait
TolerantNumerics,
a single generic factory method can produce Equivalences for any Numeric type,
but because of the Any, a separate factory method must be defined to produce an Equality
for each Numeric type.

If you just want to customize the notion of equality for ===
used in Boolean expressions, you can work with Equivalences instead of Equalitys.
If you do chose to write the more general Equalitys, they can be used wherever an Equivalence
is required, because Equality extends Equivalence, defining a final implementation of
areEquivalent that invokes areEqual.

Note: The Equality type class was inspired in part by the Equal type class of the
scalaz project.