Case Classes

    Case classes are just like regular classes with a few key differences, which are below:

    1. A case class can be created using a keyword case class instead of a simple class.

    2. Case classes promote immutability. That's why the class parameters, if not mentioned, will be public vals by default.

    case class Letter(sender: String, recipient: String, body: String)
    
    
    val message1 = Letter("Geet", "Prerna", "Lets meet in the coming week at our usual location")
    
     
    println(message1.sender)  // It will print Geet
    
    message1.sender = "Pari"  // Will give error "reassignment to val"

    Note:  It is also possible to use vars in case classes, but this is discouraged

    3. Copy method for creating new instance easily.

    message1.copy(recipient = "Nikita") 
    
    // This is going to create a new instance by just updating recipient value

    4. Provides easy Pattern matching

    case class Person(firstName: String, lastName: String)
    
    case class Pet(name: String, animal: String)
    
    val listOfPets = List(Pet("Ginger", "Dog"),
     Pet("boo", "Cat"),
     Pet("Tommy", "Dog"),
     Pet("Bow", "Dog"))
    
    listOfPets.map {
     case Pet(name, "Dog") => s"$name is a Dog"
     case _ => "The pet is not a Dog :)"
    }

    5. Instances of case classes are compared by structure and not by reference