Showing posts with label c0160| Companion Object. Show all posts
Showing posts with label c0160| Companion Object. Show all posts

hashCode() : Regular Class vs case Class

Scala compiler generates many methods including hashCode() method for case Class
scala> // Regular Class example

scala> import scala.collection.mutable.HashMap
import scala.collection.mutable.HashMap

scala> class RegularClass(var1: Int, va2: String)
defined class RegularClass

scala> val obj1 = new RegularClass(1, "one")
obj1: RegularClass = $iwC$$iwC$RegularClass@dbdbeb5

scala> obj1.hashCode()
res41: Int = 230538933

scala> val obj2 = new RegularClass(1, "one")
obj2: RegularClass = $iwC$$iwC$RegularClass@1421c757

scala> obj2.hashCode()
res42: Int = 337758039

scala> val myMap = new HashMap[RegularClass, String]
myMap: scala.collection.mutable.HashMap[RegularClass,String] = Map()

scala> val m1 = myMap + (obj1 -> "firstobject")
m1: scala.collection.mutable.Map[RegularClass,String] = Map($iwC$$iwC$RegularClass@dbdbeb5 -> firstobject)

scala> val m2 = m1 + (obj2 -> "secondobject")
m2: scala.collection.mutable.Map[RegularClass,String] = Map($iwC$$iwC$RegularClass@dbdbeb5 -> firstobject, $iwC$$iwC$RegularClass@1421c757 -> secondobject)

scala>
     | // case Class example

scala> import scala.collection.mutable.HashMap
import scala.collection.mutable.HashMap

scala> case class MyCaseClass(var1: Int, va2: String)
defined class MyCaseClass

scala> val obj1 = new MyCaseClass(1, "one")
obj1: MyCaseClass = MyCaseClass(1,one)

scala> obj1.hashCode()
res44: Int = 1311424316

scala> val obj2 = new MyCaseClass(1, "one")
obj2: MyCaseClass = MyCaseClass(1,one)

scala> obj1.hashCode()
res45: Int = 1311424316

scala> val myMap = new HashMap[MyCaseClass, String]
myMap: scala.collection.mutable.HashMap[MyCaseClass,String] = Map()

scala> val m1 = myMap + (obj1 -> "firstobject")
m1: scala.collection.mutable.Map[MyCaseClass,String] = Map(MyCaseClass(1,one) -> firstobject)

scala> //Because both obj1 & obj2 are considered to be the same

scala> // key ; obj1 is overwritten by obj2

scala> val m2 = m1 + (obj2 -> "secondobject")
m2: scala.collection.mutable.Map[MyCaseClass,String] = Map(MyCaseClass(1,one) -> secondobject)

equals() : Regular class vs Case Class

Scala Compiler automatically generates many methods including equals() method for case class
scala> // Regular Class example

scala> class RegularClass(var1: Int)
defined class RegularClass

scala> val obj1 = new RegularClass(1)
obj1: RegularClass = $iwC$$iwC$RegularClass@49ea136d

scala> val obj2 = new RegularClass(1)
obj2: RegularClass = $iwC$$iwC$RegularClass@471e8ede

scala> obj1 == obj2
res3: Boolean = false

scala>

scala> // Case Class example

scala> case class MyCaseClass(var1: Int)
defined class MyCaseClass

scala> val obj1 = new MyCaseClass(1)
obj1: MyCaseClass = MyCaseClass(1)

scala> val obj2 = new MyCaseClass(1)
obj2: MyCaseClass = MyCaseClass(1)

scala> obj1 == obj2
res4: Boolean = true

Case Class & Companion Object

A Class coupled with its Companion Object can be used to implement Factory Pattern. Let us checkout a use case without Case Class
scala> :paste
// Entering paste mode (ctrl-D to finish)

// c116 -> a15
//== Understanding Companion object ================

// **Here 'object DbConnector' is a Companion object for
// 'class DbConnector'
class DbConnector {
  val url = "jdbc://..."
  val db = "mydb"
  val user = "myusername"
  val pwd = "mypwd"
  def connect()  = { println ("Connecting to DB...") }
}

object DbConnector {
  def apply() = new DbConnector()
}

// ** Note here we are not using new() to create
// an object for 'class DbConnector'. This is an
// example of Factor pattern
val conn = DbConnector()

// Exiting paste mode, now interpreting.

defined class DbConnector
defined module DbConnector
conn: DbConnector = DbConnector@208279af

scala> conn.connect()
Connecting to DB...
A Case class simplifies this process further. The Scala compiler provides Companion object without the need for us to explicitly providing the Companion object
scala> // c116 -> a20

scala> //== Case Class : Compiler creates a Companion object for 'case class'

scala> //== (without us explicity providing a Companion object)

scala> //==              there by implementing factor pattern

scala> case class DbConnectorV2 {
     |   val url = "jdbc://..."
     |   val db = "mydb"
     |   val user = "myusername"
     |   val pwd = "mypwd"
     |   def connect()  = { println ("Connecting to DB...") }
     | }
warning: there were 1 deprecation warning(s); re-run with -deprecation for details
defined class DbConnectorV2

scala> // ** Note : Here also we are not using new(). So this is an example

scala> //           of factory pattern

scala> val conn = DbConnectorV2()
conn: DbConnectorV2 = DbConnectorV2()

scala> conn.connect()
Connecting to DB...
The compiler also generates toString(), hashCode(), equals() & apply() among many methods for the case class