/
Equality.scala
257 lines (250 loc) · 12.8 KB
/
Equality.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/*
* Copyright 2001-2013 Artima, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.scalactic
/**
* Defines a custom way to determine equality for a type when compared with another value of type <code>Any</code>.
*
* <p>
* <code>Equality</code> enables you to define alternate notions of equality for types that can be used
* with ScalaUtil's <code>===</code> and <code>!==</code> syntax and ScalaTest's matcher syntax.
* </p>
*
* <p>
* For example, say you have a case class that includes a <code>Double</code> value:
* </p>
*
* <pre class="stREPL">
* scala> case class Person(name: String, age: Double)
* defined class Person
* </pre>
*
* <p>
* Imagine you are calculating the <code>age</code> 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:
* </p>
*
* <pre class="stREPL">
* scala> import org.scalactic._
* import org.scalactic._
*
* scala> import TripleEquals._
* import TripleEquals._
*
* scala> Person("Joe", 29.0001) === Person("Joe", 29.0)
* res0: Boolean = false
* </pre>
*
* <p>
* The <code>===</code> operator looks for an implicit <code>Equality[L]</code>, where <code>L</code> is the left-hand type: in this
* case, <code>Person</code>. Because you didn't specifically provide an implicit <code>Equality[Person]</code>, <code>===</code> will fall back on
* <a href="#defaultEquality">default equality</a>, which will call <code>Person</code>'s <code>equals</code> method. That <code>equals</code> method, provided by the Scala compiler
* because <code>Person</code> is a case class, will declare these two objects unequal because 29.001 does not exactly equal 29.0.
* </p>
*
* <p>
* To make the equality check more forgiving, you could define an implicit <code>Equality[Person]</code> that compares
* the <code>age</code> <code>Double</code>s with a tolerance, like this:
* </p>
*
* <pre class="stREPL">
* scala> import Tolerance._
* import Tolerance._
*
* scala> implicit val personEq =
* | new Equality[Person] {
* | def areEqual(a: Person, b: Any): Boolean =
* | b match {
* | case p: Person => a.name == p.name && a.age === p.age +- 0.0002
* | case _ => false
* | }
* | }
* personEq: org.scalactic.Equality[Person] = $anon$1@2b29f6e7
* </pre>
*
* <p>
* Now the <code>===</code> operator will use your more forgiving <code>Equality[Person]</code> for the equality check instead
* of default equality:
* </p>
*
* <pre class="stREPL">
* scala> Person("Joe", 29.0001) === Person("Joe", 29.0)
* res1: Boolean = true
* </pre>
*
* <a name="defaultEquality"></a>
* <h2>Default equality</h2>
*
* <p>
* Scalactic defines a default <code>Equality[T]</code> for all types <code>T</code> whose <code>areEqual</code> method works by first
* calling <code>.deep</code> on any passed array, then calling <code>==</code> on the left-hand object, passing in the right-hand object.
* You can obtain a default equality via the <code>default</code> method of the <a href="Equality$.html">Equality companion object</a>,
* or from the <code>defaultEquality</code> method defined in <a href="TripleEqualsSupport.html"><code>TripleEqualsSupport</code></a>.
* </p>
*
* <a name="aboutEquality"></a>
* <h2>About equality and equivalence</h2>
*
* <p>
* The <code>Equality</code> trait represents the Java Platform's native notion of equality, as expressed in the signature and contract of
* the <code>equals</code> method of <code>java.lang.Object</code>. Essentially, trait <code>Equality</code> enables you to write alternate
* <code>equals</code> method implementations for a type outside its defining class.
* </p>
*
* <p>
* In an <code>equals</code> method, the left-hand type is known to be the type of <code>this</code>, but
* the right-hand type is <code>Any</code>.
* 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 (<code>this</code>) object.
* An an illustration, here's a possible <code>equals</code>
* implementation for the <code>Person</code> case class shown in the earlier example:
* </p>
*
* <pre class="stHighlighted">
* <span class="stReserved">override</span> <span class="stReserved">def</span> equals(other: <span class="stType">Any</span>): <span class="stType">Boolean</span> =
* other <span class="stReserved">match</span> {
* <span class="stReserved">case</span> p: <span class="stType">Person</span> => name = p.name && age = p.age
* <span class="stReserved">case</span> _ => <span class="stReserved">false</span>
* }
* </pre>
*
* <p>
* The <code>areEquals</code> method of <code>Equality[T]</code> is similar. The left-hand type is known to be <code>T</code>, but the right-hand type is <code>Any</code>, so
* normally you'd need to do a runtime type test in your <code>areEqual</code> implementation.
* Here's the <code>areEqual</code> method implementation from the earlier <code>Equality[Person]</code> example:
* </p>
*
* <pre class="stHighlighted">
* <span class="stReserved">def</span> areEqual(a: <span class="stType">Person</span>, b: <span class="stType">Any</span>): <span class="stType">Boolean</span> =
* b <span class="stReserved">match</span> {
* <span class="stReserved">case</span> p: <span class="stType">Person</span> => a.name == p.name && a.age === p.age +- <span class="stLiteral">0.0002</span>
* <span class="stReserved">case</span> _ => <span class="stReserved">false</span>
* }
* </pre>
*
* <p>
* <code>Equality</code> is used by <a href="TripleEquals.html"><code>TripleEquals</code></a>, which enforces no type constraint between the left and right values, and the
* <code>equal</code>, <code>be</code>, and <code>contain</code> syntax of ScalaTest Matchers.
* </p>
*
* <p>
* By contrast, <a href="TypeCheckedTripleEquals.html"><code>TypeCheckedTripleEquals</code></a>
* and <a href="ConversionCheckedTripleEquals.html"><code>ConversionCheckedTripleEquals</code></a> use an <a href="Equivalence.html"><code>Equivalence</code></a>.
* <code>Equivalence</code> differs from <code>Equality</code> in that both the left and right values are of the same type. <code>Equivalence</code> works for
* <code>TypeCheckedTripleEquals</code> 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 <em>widens</em> the subtype to the supertype. So ultimately, both left and right sides are of the supertype type. Similarly, <code>Equivalence</code>
* works for <code>ConversionCheckedTripleEquals</code> 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 <code>Predef</code> 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 <code>Equivalence</code>'s <code>areEquivalent</code>
* method might look:
* </p>
*
* <pre class="stHighlighted">
* <span class="stReserved">def</span> areEquivalent(a: <span class="stType">Person</span>, b: <span class="stType">Person</span>): <span class="stType">Boolean</span> =
* a.name == b.name && a.age === b.age +- <span class="stLiteral">0.0002</span>
* </pre>
*
* <p>
* Scalactic provides both <code>Equality</code> and <code>Equivalence</code> because the <code>Any</code> in
* <code>Equality</code> can sometimes make things painful. For example, in trait
* <a href="TolerantNumerics.html"><code>TolerantNumerics</code></a>,
* a single generic factory method can produce <code>Equivalence</code>s for any <code>Numeric</code> type,
* but because of the <code>Any</code>, a separate factory method must be defined to produce an <code>Equality</code>
* for each <code>Numeric</code> type.
* </p>
*
* <p>
* If you just want to customize the notion of equality for <code>===</code>
* used in <code>Boolean</code> expressions, you can work with <code>Equivalence</code>s instead of <code>Equality</code>s.
* If you do chose to write the more general <code>Equality</code>s, they can be used wherever an <code>Equivalence</code>
* is required, because <code>Equality</code> extends <code>Equivalence</code>, defining a final implementation of
* <code>areEquivalent</code> that invokes <code>areEqual</code>.
* </p>
*
* <p>
* <em>Note: The <code>Equality</code> type class was inspired in part by the <code>Equal</code> type class of the
* <a href="http://github.com/scalaz/scalaz" target="_blank"><code>scalaz</code></a> project.</em>
* </p>
*
* @tparam A the type whose equality is being customized
*/
trait Equality[A] extends Equivalence[A] {
/*
* <p>
* The <code>equals</code> method of <code>java.lang.Object</code> and <code>areEqual</code> method of trait <code>Equality</code> have a similar
* signatures and behavior, and you write them in a similar way.
* When using <a href="TypeCheckedTripleEquals.html"><code>TypeCheckedTripleEquals</code></a> or
* <a href="ConversionCheckedTripleEquals.html"><code>ConversionCheckedTripleEquals</code></a>, however,
* </p>
*
*/
/**
* Indicates whether the objects passed as <code>a</code> and <code>b</code> are equal.
*
* @param a a left-hand value being compared with another (right-hand-side one) for equality (<em>e.g.</em>, <code>a == b</code>)
* @param b a right-hand value being compared with another (left-hand-side one) for equality (<em>e.g.</em>, <code>a == b</code>)
* @return true if the passed objects are "equal," as defined by this <code>Equality</code> instance
*/
def areEqual(a: A, b: Any): Boolean
/**
* A final implementation of the <code>areEquivalent</code> method of <code>Equivalence</code> that just passes
* <code>a</code> and <code>b</code> to <code>areEqual</code> and returns the result.
*
* <p>
* This method enables any <code>Equality</code> to be used where an <code>Equivalence</code> is needed, such
* as the implicit enabling methods of <a href="TypeCheckedTripleEquals.html"><code>TypeCheckedTripleEquals</code></a>
* and <a href="ConversionCheckedTripleEquals.html"><code>ConversionCheckedTripleEquals</code></a>.
* </p>
*
* @param a a left-hand value being compared with another, right-hand, value for equality (<em>e.g.</em>, <code>a == b</code>)
* @param b a right-hand value being compared with another, left-hand, value for equality (<em>e.g.</em>, <code>a == b</code>)
* @return true if the passed objects are "equal," as defined by the <code>areEqual</code> method of this
* <code>Equality</code> instance
*/
final def areEquivalent(a: A, b: A): Boolean = areEqual(a, b)
}
/**
* Companion object for trait <code>Equality</code> that provides factory methods for producing <code>Equality</code>
* instances.
*/
object Equality {
/**
* Produces a <code>NormalizingEquality[A]</code> whose <code>normalized</code>,
* <code>normalizedCanHandle</code>, and <code>normalizedOrSame</code> methods delegate
* to the passed <code>Uniformity[A]</code>.
*
* @tparam A the type of passed <code>Uniformity</code> and returned <code>NormalizingEquality</code>.
* @param uniformity the <code>Uniformity</code> to which the returned <code>NormalizingEquality</code>
* should delegate.
*/
def apply[A](uniformity: Uniformity[A]): NormalizingEquality[A] = {
new NormalizingEquality[A] {
def normalized(a: A): A = uniformity.normalized(a)
def normalizedCanHandle(b: Any): Boolean = uniformity.normalizedCanHandle(b)
def normalizedOrSame(b: Any): Any = uniformity.normalizedOrSame(b)
}
}
/**
* Provides default <code>Equality</code> implementations for the specified type whose
* <code>areEqual</code> method first calls <code>.deep</code> on any <code>Array</code> (on either the left or right side),
* then compares the resulting objects with <code>==</code>.
*
* @return a default <code>Equivalence[A]</code>
*/
implicit def default[A]: Equality[A] = new DefaultEquality[A]
}