Saturday, August 10, 2013

Object Equality in Scala

Object equality has been confusing developers right since its inception (OOP).
What is object equality? Well! It has different meanings in different contexts. Lets start listing the contexts and scenarios where object equality makes sense

1) "Equality" in terms of object references.
This is the least used equality context and the scenarios include
a) When one wants to check whether two objects references point to the same object or not. If they do, then the output is a true else a false.
           e.g1: val a = new Product(1,2)
                    val b = new Product(3,4)
If referential equality is applied between 'a' & 'b' then the output would be 'false' because                       'a' & 'b' refer two different objects in memory.
Scala language has a special operator which is only used to assess referential equality                             between two objects. The operator is "eq" .
In the above example a eq b returns false as 'a' and 'b' point to two different objects in                             memory.

Lets have another example:
          e.g2: val a = new String("Sandeep") 
                   val b = new String("Sandeep")
                 
Just like the previous example, the expression a eq b returns a false even though the String
constructor has the same string "Sandeep". This is because the 'new' operator creates a new                   String object every time new String() constructor is called.

Consider this example
           e.g3: val a = "Sandeep"
                    val b = "Sandeep"
Any String is immutable is Scala, be it created using the new operator or created using the                       "" operator. The expression a eq b returns a true in this scenario. The reason is that when                       ever a String is created with the "" operator, it is internalized, meaning that the JVM keeps                     track of all the similar strings and stores them in a special location. The size of this location                     can be sent as a JVM argument using -XX:StringTableSize=n , where n is the number of                       bytes you want to allocate to interned strings.

Therefore, whenever the "same" new String "vals" are created using the "" operator, the                        JVM makes sure it points all of the references to the interned Strings. This way the memory                    is optimized.

Coming back to our equality discussion, in this example, since the vals 'a' & 'b' point to the                   same interned String, the expression a eq b returns true.

2) "Equality" in terms of natural equality
Sometimes, or even more often, we run into situations where natural equality makes more                     sense than anything else. The scenarios are comparing two integers, comparing two Strings,                   comparing floats, comparing Double or even Boolean etc. Scala has a special method "=="                  which is used for assessing natural equality of objects in Scala.

e.g1: val a == 1
         val b == 2
The expression a == b evaluates to false
                         
e.g2:  val a = 2
          val b = 2
The expression a ==b here, evaluates to true. This is because the only thing the                                       method "==" does here is check for natural equality.

e.g3:  case class Product(val x:Int, val y:Int)
          val a = new Product(1,2)
          val b = new Product(1,2)
The expression a==b here, evaluates to true. This operator "==" is again making                                     a pure natural check on the objects (The object type, the values in the constructors)

e.g4:  case class Product(val x:Int, val y:Int)
          val a = Product(1,2)
          val b = Product(3,4)
The expression a==b here, evaluates to falseThis operator "==" is again making                                   a pure natural check on the objects (The object type is same, but the values in the                                   constructors are different, therefore returns false)
e,g5:  val a = "Sandeep"
          val b = "Sandeep"
The expression a==b here, evaluates to true (In JAVA it evaluates to False as there is                             no natural comparison happening there. We use either "equals" or                                                         "equalsIgnoreCase" methods for natural equality where Strings are used)

The "==" method is of type 'final' and therefore cannot be overridden. This is                                         designed this way to help developers have a choice when they come across                                             dealing with natural equality. They need not go for other methods to check for simple                             natural equality. The "equals" method in objects can be overridden to change the behavior of the "==". Therefore the "==" and the "equals" method are linked. By overriding "equals" method, the behavior of "==" can be changed. By doing this, we give the "==" method the equality behavior we mean, and which makes more sense to us. We will speak about the "equals" method in the next part below.

3) "Equality" in terms of the state of an object w.r.t the other
This is a more widely used and often confusing concept on object equality.

Every object (in Java & Scala) have default implementations of the method "equals". The default implementation here is nothing but a natural check on the objects (checking for its type and for its values in the constructor). But, we might want to add more to assess equality rather than just checking its type and the values in the constructor. This is where the state of the object is used to assess equality.
An example would clear the confusion here.

e.g1:
class Product(val x:Int, y:Int) {
           override equals(obj:Any):Boolean = obj match {
              case obj:Product => this.x==obj.x && this.y==obj.y
              case _ => false
      }
}
Lets test the class by instantiating some objects
val a = new Product(1,2)
val b = new Product(2,3)

"a equals b" returns a false.


Here in this above example, there is a class by the name "Product" and which takes a constructor with values x & y.  The definition of equality which we have overridden here is that the values of x and y in the callee object are checked for equality with the corresponding values of x & y respectively in the caller object. This  is just a custom definition of equality of objects of type Product which we have come up with, as per our requirement. 


Lets consider another example

e.g2:
import Math._
class Complex(val real:Float, imag:Float) {
         override equals(obj:Any):Boolean = obj match {
             case obj:Product =>sqrt (this.real*this.real + this.imag*this.imag) == sqrt (obj.real*obj.real +                                                  obj.imag*obj.imag)
             case _ => false
     }

}

In the above example we have a class which represents Complex numbers. The constructor takes a real part and an imaginary part as values. The definition of equality we have overridden here is that the resultant of the caller object should be same as the resultant of the callee object. RESULTANT is (Square root of the sum of the squares of the real and imaginary parts)

To test the above class for equality, lets initialize a couple
val a = new Complex(3,4)
val b = new Complex(5,0)


a equals b returns a true (even though the values in the constructors are very different). The resultant of (3,4) is 5 and the resultant of (5,0) is also 5.










Thursday, August 1, 2013

Different Variant of the Custom (typed) Map implementation


trait MyMap[K,V]{
def +(k:K,v:V):MyMap[K,V]
def get(x:K):V
def keys:List[K]
def values:List[V]
def length:Int
}
object MyMap {

def apply[K,V](x:Tuple2[K,V]*): MyMap[K,V] = new MyMapImpl[K,V](x.toList);
class MyMapImpl[K,V](xs:List[Tuple2[K,V]]) extends MyMap[K,V] {

def +(k:K,v:V):MyMap[K,V] = new MyMapImpl[K,V](Tuple2(k,v)::xs)
def get(k:K):V = (xs find (m=>m._1==k)) match {
case Some(x) => x._2
}
def keys:List[K] = xs map (m=>m._1)
def values:List[V] = xs map (m=>m._2)
def length:Int = xs length
}

}

def myTest {

var x = MyMap((1,2),(3,4),(33,56))
println(x  get 33)

x += (35,44) // Adds a new (key, value) pair to the map x
println(x get 35) // Prints 44 (value)

println("Keys-->>"+x.keys.toString) // prints List(1,3,33)
println("Values-->>"+x.values.toString) // prints List(2,4,56,44)
println("Length-->>"+x.length) // prints 4 which is the size of the custom typed map.
}
myTest


Explanation:

My previous version of the custom (typed) map implementation -->>http://dailyscala.blogspot.com/2013/06/create-your-own-typed-map-in-scala.html

The example in the link above uses more imperative style in implementing the map methods but Scala provides many functional ways to implement the + , get, keys and values methods. Lets take them one by one

1)The + method takes two inputs (a,b) where a is the key and b is the value. The implementation takes these two values, converts them into a tuple of the form Tuple2[K,V] and cons (::) it to the original list and returns it. The type of the list returned will be List[Tuple2[K,V]]

2) The "get" method is the most interesting part of the program. This method takes input of type K (here it is "k"), which is the key and returns a value of type V, which is the value. The find operation is called on the current list and the predicate used processes each element of the list (which is a Tuple2), extracts the first element using the ._1 method and compares it with the key "k". The find returns the first element of the list which satisfies the predicate. The returned element will be of the type Option or more specifically Option[Tuple2[K,V]]. Next, this Option value is piped into a pattern match block and the value is matched against Some(x) and the value x is returned as the matching value to the key "k".

3) The "keys" method returns a list of all the keys inside the custom implemented Map. The implementation of this method is as follows=> The map method is applied to the list of tuples. A map applies a predicate to all the elements of the list. The predicates converts the element to a different form.
For e.g: List(1,2,3) map _+1  will return the list List(2,3,4). Here each element of the list is converted to a different element using the predicate "_+1". Similarly, in the custom map, each element of the list (Tuple2) is converted into a type K using the predicate "m=>m._1". Here "m" is the Tuple and m._1 is the first value of the Tuple, which is the "key". The new list of all the converted values is returned. The type of the returned list will be List[K]

4) The "values" method also is similarly written as the "keys" method above.