Search code examples
scalapattern-matchingcase-class

What is difference between Constructor pattern and variable binding pattern in scala match expression?


In Scala I am trying to understand pattern matching ,however most of the patterns are self explanatory but constructor pattern and variable binding pattern looks confusing to me . I tried following example from Programming Scala ,2ed

case class Address(street: String, city: String, country: String)
case class Person(name: String, age: Int, address: Address) 

object ScalaCaseDemoMain extends App{

    val alice   = Person("Alice",   25, Address("1 Scala Lane", "Chicago", "USA"))
    val bob     = Person("Bob",     29, Address("2 Java Ave.",  "Miami",   "USA"))
    val charlie = Person("Charlie", 32, Address("3 Python Ct.", "Boston",  "USA"))

    for (person <- Seq(alice, bob, charlie)) {
    person match {
        case p @ Person("Alice", 25, address) => println(s"Hi Alice! $p")
        case p @ Person("Bob", 29, a @ Address(street, city, country)) =>
        println(s"Hi ${p.name}! age ${p.age}, in ${a.city}")
        case p @ Person(name, age, _) =>
      println(s"Who are you, $age year-old person named $name? $p")
  }
}

    }

I want to know when to use constructor pattern

case Person("Alice", 25, address) => //some action here

and when to use variable binding pattern

case p @ Person("Alice", 25, address) //some action here

I am always confused while It comes to pattern matching ?


Solution

  • Constructor vs Extractor

    The pattern you call constructor is in most cases called an Extractor or Deconstructor. It is like a reversed constructor as you can see by the method it calls unapply.

    If it would occur on the right hand side or outside the pattern match it would be as you noted a Constructor.

    Answer

    @ only is used in pattern matching to bind the deconstructed entity to a variable. It's purpose is to supplies the option to catch the whole expression and still be able to use extracted values in later steps.

    So there would always be a way to arrange the code in a way that you would not need to use @ but it could help readability a lot.

    Example

    An usage example for @ is: You want to send a mail to all Persons named "Alice" which are older than "21" but the address is no important selection criterium.

    case p @ Person("Alice", age, _) if age > 21 => storePersonForMailing(p)
    

    Here the pattern match shows clearly your intention by stressing the values you use for the selection and as you need the address later for sending the mail it would be no good idea to drop it.