Before we proceed to learn about Apply and Unapply methods, its good to know what a companion object is. A companion object in Scala for some class say Fraction is defined as:

class Fraction(var numerator:Int, var denominator:Int){ def *(fraction2:Fraction) = { Fraction(this.numerator*fraction2.numerator, this.denominator*fraction2.denominator) } override def toString = this.numerator+"/"+this.denominator } //the below construct is the companion object for Fraction class. object Fraction{ }

One can provide apply(args) and unapply(args) methods in the companion objects which can be used implemented to some special operations in Scala. Suppose for example you wish to create a Fraction instead as below:

val fraction1 = Fraction(3,4)

the above line behind the scenes invokes the apply method provided in the companion object for Fraction. Similarly suppose I want to extract the contents of an instance and assign them to another object, something like:

val fract1 = Fraction(3,4) val fract2 = Fraction(2,4) val Fraction(numer, denom) = fract1 * fract2 println("Numerator: "+numer+" Denominator: "+denom)

the above code invokes the unapply() method behind the scenes.

In the apply method we take the required parameters and return the new instance of class we are interested in where as we do the reverse in unapply- we take the instance and extract out the required information and return them in the form of a tuple.

Lets add those methods in the Fraction object

object Fraction{ def apply(numer:Int, denom:Int) = new Fraction(numer,denom) def unapply(fraction:Fraction) = { if ( fraction == null ) None else Some(fraction.numerator, fraction.denominator) } }

Check this out if you are curious about Some and None. The idea is simple- in apply method take the parameter required and then return a new Fraction instance and in the unapply extract the values in the fields of the object and then return those values. Lets see these things in action:

object Main extends App{ println(Fraction(3,4) * Fraction(2,4) ) val Fraction(numer, denom) = Fraction(1,4) * Fraction(4,5) println("Numerator: "+numer+" Denominator: "+denom) }

The output:

6/16 Numerator: 4 Denominator: 20

Lets see other examples of how the apply and unapply methods can be used. There’s another method called: unapplySeq which can be used to extract an arbitrary sequence of values. We can use unapply to extract any data from the given data. This is particularly useful in pattern matching where Case classes as used. Case classes already implement these apply and unapply methods.

object Name{ def unapply(input:String) = { val pos = input.indexOf(" ") if ( pos == -1 ) None else Some(input.substring(0,pos), input.substring(pos+1)) } } object Main extends App{ val personName = "FirstName LastName" val Name(firstName, lastName) = personName println(firstName+" Last: "+lastName) }

In the above code we extract the first name and last name from the given name assuming the first and last name are made up of one word respectively.

also read: