result management system report for college project
Equality For All!
1. Equality For All!
Scala by the Bay, 2014
BillVenners
Artima, Inc.
Escalate Software
Saturday, August 9, 2014
2. Equality: An equivalence relation with
one element per equivalence class
42 4341
42 = 4241 = 41 43 = 43
reflexive: x = x
symmetric: x = y iff y = x
transitive: if x = y and y = z then x = z
Saturday, August 9, 2014
3. How do I say forty two in code?
Let me count the ways...
42
42L
42.0
42.0F
42.toShort
'*'
42.toByte BigInt(42)
BigDecimal(42)
new java.lang.Integer(42)
new java.lang.Long(42L)
new java.lang.Double(42.0)
new java.lang.Float(42.0F) new java.lang.Short(42.toShort)
new java.lang.Character(42)
new java.lang.Byte(42.toByte)
new java.math.BigInteger("42")
new java.math.BigDecimal(42) Complex(42.0, 0.0)
DigitString("42") DigitString("042")
Saturday, August 9, 2014
4. The equals method implements an equivalence relation on non-null object references:
• It is reflexive: for any non-null reference value x, x.equals(x) should return true.
• It is symmetric: for any non-null reference values x and y, x.equals(y) should return true
if and only if y.equals(x) returns true.
• It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true
and y.equals(z) returns true, then x.equals(z) should return true.
• It is consistent: for any non-null reference values x and y, multiple invocations of
x.equals(y) consistently return true or consistently return false, provided no
information used in equals comparisons on the objects is modified.
• For any non-null reference value x, x.equals(null) should return false.
Java's equals contract
public boolean equals(Object obj)
final def == (other:Any): Boolean
Saturday, August 9, 2014
8. scala> "forty two" == 42
res19: Boolean = false
scala> List(mutable.Set(Map(Some(4L) -> BigInt(2)))) ==
Vector(Set(mutable.Map(Some("4.0") -> new java.lang.Long(2L))))
res23: Boolean = false
Wanted: Type errors
But how to decide which comparisons compile?
Saturday, August 9, 2014
9. scala> "forty two" == 42
<console>:20: error: types String and Int do not adhere to the
type constraint selected for the === and !== operators; the
missing implicit parameter is of type
org.scalactic.EqualityConstraint[String,Int]
"forty two" === 42
^
scala> BigInt(42) === BigDecimal(42)
res1: Boolean = true
Fail to compile if L can never equal R.
Saturday, August 9, 2014
10. scala> Vector.empty === List.empty
<console>:20: error: ambiguous implicit values:
both method conflictingEmptySeqConstraint1 in object EqualityConstraint of type [LSEQ[e] <:
scala.collection.GenSeq[e], RSEQ[e] <: scala.collection.GenSeq[e]]=>
org.scalactic.EqualityConstraint[LSEQ[Nothing],RSEQ[Nothing]]
and method conflictingEmptySeqConstraint2 in object EqualityConstraint of type [LSEQ[e] <:
scala.collection.GenSeq[e], RSEQ[e] <: scala.collection.GenSeq[e]]=>
org.scalactic.EqualityConstraint[LSEQ[Nothing],RSEQ[Nothing]]
match expected type
org.scalactic.EqualityConstraint[scala.collection.immutable.Vector[A],List[Nothing]]
Vector.empty === List.empty
^
scala> Vector.empty === List.empty[Int]
res3: Boolean = true
scala> Vector.empty[String] === List.empty
res4: Boolean = true
Fail to compile if L will always equal R.
Saturday, August 9, 2014
11. Candidate rule:
To compile, an equality comparison
must be interesting: values of types L
and R can be either equal or unequal.
Saturday, August 9, 2014
12. scala> case class Complex(real: Double, imaginary: Double)
defined class Complex
scala> implicit def convertIntToComplex(i: Int): Complex = Complex(i, 0.0)
convertIntToComplex: (i: Int)Complex
scala> 42 === Complex(42, 0)
<console>:24: error: types Int and Complex do not adhere to the type constraint selected for the
=== and !== operators; the missing implicit parameter is of type
org.scalactic.EqualityConstraint[Int,Complex]
42 === Complex(42, 0)
^
scala> Complex(42, 0) === 42
<console>:24: error: types Complex and Int do not adhere to the type constraint selected for the
=== and !== operators; the missing implicit parameter is of type
org.scalactic.EqualityConstraint[Complex,Int]
Complex(42, 0) === 42
^
What about implicit conversions?
Saturday, August 9, 2014
13. scala> implicit val enabler = EqualityEnabledBetween[Int, Complex]
enabler: org.scalactic.EqualityEnabledBetween[Int,Complex] =
org.scalactic.EqualityEnabledBetween@e5d2d9b
scala> 42 === Complex(42, 0)
res2: Boolean = true
scala> Complex(42, 0) === 42
res3: Boolean = true
scala> new AnyShouldWrapper(1) === 1 // Probably shouldn't enable...
Intuition: enable some but not all
But what would the rule be?
Saturday, August 9, 2014
14. OK if the conversion is an injection
scala> case class DigitString(digits: String) {
| val toInt: Int = digits.toInt
| }
defined class DigitString
scala> implicit def convert(d: DigitString): Int =
| d.digits.toInt
convertDigitStringToInt: (d: DigitString)Int
scala> DigitString("42") === DigitString("042")
res0: Boolean = false
scala> DigitString("42").toInt === DigitString("042").toInt
res1: Boolean = true
John C. Reynolds: Using category theory to design implicit conversions and generic operators.
Saturday, August 9, 2014
15. How to decide:
1.To compile, an equality comparison must be
interesting: values of types L and R can be either
equal or unequal.
2.Allow select implicit conversions to be enabled,
and recommend that non-widening conversions
(non-injections) not be enabled.
Saturday, August 9, 2014
16. scala> (Some(1): Option[Int]) === Some(1)
res0: Boolean = true
scala> Some(1) === (Some(1): Option[Int])
res1: Boolean = true
scala> Some(1) === Some(1)
res2: Boolean = true
What about the implicit conversion
from subtype to supertype (<:<)?
Saturday, August 9, 2014
17. scala> def eqv[T](a: T, b: T): Boolean = a === b
eqv: [T](a: T, b: T)Boolean
scala> eqv(1, ())
res3: Boolean = false
scala> ((i: Int) => i + 1) === ((i: Int) => i + 1)
res4: Boolean = false
Even though <:< is an injection, is it
always desireable?
Saturday, August 9, 2014
19. scala> import EnabledEquality._
import EnabledEquality._
scala> def eqv[T](a: T, b: T): Boolean = a === b
<console>:19: error: types T and T do not adhere to the type constraint selected for
the === and !== operators; the missing implicit parameter is of type
org.scalactic.EqualityConstraint[T,T]
def eqv[T](a: T, b: T): Boolean = a === b
^
scala> ((i: Int) => i + 1) === ((i: Int) => i + 1)
<console>:20: error: types Int => Int and Int => Int do not adhere to the type
constraint selected for the === and !== operators; the missing implicit parameter is
of type org.scalactic.EqualityConstraint[Int => Int,Int => Int]
((i: Int) => i + 1) === ((i: Int) => i + 1)
^
EnabledEquality benefit
Saturday, August 9, 2014
20. scala> case class Person(name: String)
defined class Person
scala> Person("Sue") === Person("Sue")
<console>:22: error: types Person and Person do not adhere to the type constraint
selected for the === and !== operators; the missing implicit parameter is of type
org.scalactic.EqualityConstraint[Person,Person]
Person("Sue") === Person("Sue")
^
scala> implicit val enabler = new EqualityEnabledFor[Person]
enabler: org.scalactic.EqualityEnabledFor[Person] =
org.scalactic.EqualityEnabledFor@1289d391
scala> Person("Sue") === Person("Sue")
res2: Boolean = true
EnabledEquality cost
Saturday, August 9, 2014
21. scala> 1 should === ("one")
<console>:23: error: types Int and String do not adhere to the type constraint selected for the === and !==
operators; the missing implicit parameter is of type org.scalactic.Constraint[Int,String]
1 should === ("one")
^
scala> 1 should equal ("one")
<console>:23: error: could not find implicit value for parameter typeClass1:
org.scalactic.enablers.EvidenceThat[String]#CanEqual[Int]
1 should equal ("one")
^
scala> 1 should be ("one")
<console>:23: error: could not find implicit value for parameter typeClass1:
org.scalactic.enablers.EvidenceThat[String]#CanEqual[Int]
1 should be ("one")
^
scala> 1 should be_== ("one")
org.scalatest.exceptions.TestFailedException: 1 was not equal to "one"
ScalaTest's equal, be, and be_==
Saturday, August 9, 2014
22. scala> List(1, 2, 3) should contain ("one")
<console>:23: error: could not find implicit value for parameter typeClass1:
org.scalactic.enablers.EvidenceThat[String]#CanBeContainedIn[List[Int]]
List(1, 2, 3) should contain ("one")
^
scala> List(1, 2, 3) should contain oneOf ("one", "two")
<console>:23: error: could not find implicit value for parameter evidence:
org.scalactic.enablers.EvidenceThat[String]#CanBeContainedIn[List[Int]]
List(1, 2, 3) should contain oneOf("one", "two")
^
scala> 1 isIn List(1, 2, 3)
res14: Boolean = true
scala> "one" isIn List(1, 2, 3)
<console>:23: error: Could not find evidence that String can be contained in List[Int]; the missing implicit
parameter is of type org.scalactic.enablers.ContainingConstraint[List[Int],String]
"one" isIn List(1, 2, 3)
^
ScalaTest's contain, Scalactic's isIn/isNotIn
Saturday, August 9, 2014
23. if sufficientTimeRemains then (Q => A) else thanks
artima.com/shop
15% discount
coupon code:
BYTHEBAY2014
Saturday, August 9, 2014
24. scala> 1L === 1
res0: Boolean = true
scala> 1 === 1L
<console>:14: error: could not find implicit value for parameter F0:
scalaz.Equal[Any]
1 === 1L
^
Scalaz or Spire
Scalactic
scala> 1L === 1
res7: Boolean = true
scala> 1 === 1L
res8: Boolean = true
Equal[T], Eq[T]
EqualityConstraint[L, R]
Equivalence[T]
Saturday, August 9, 2014