Q1. Given the below Person.scala file with Person.calss, what will be the output?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package com.sbthello //a class - you create instance of a class, which become objects class Person(name: String, age: Int, salary: BigDecimal) { println("This is printed when the object is created " + this) def calcBonus(bonus: BigDecimal) : BigDecimal = salary + bonus def getNameLength():Int = name.length() } object Test extends App { val person1 = new Person("John", 25, BigDecimal(250.00)) } |
A1. It prints the below text as when a Scala class is instantiated the statements in the body are executed after the object is constructed via the constructor defined in the class signature itself as “Person(name: String, age: Int, salary: BigDecimal)”. The functions calcBonus(..), getNameLength(), etc apply to the objects (i.e. instances of a class) created with the “new” keyword.
Output:
1 2 3 |
This is printed when the object is created com.sbthello.Person@29453f44 |
Q2. How will you define static methods in Scala?
A2. Using an Object, which is a singleton. In the above example “Test” is an object, and it extends App so that you get the main method for free to run the application. The above code can be rewritten with the static main method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package com.sbthello //a class - you create instance of a class, which become objects class Person(name: String, age: Int, salary: BigDecimal) { println("This is printed when the object is created " + this) def calcBonus(bonus: BigDecimal): BigDecimal = salary + bonus def getNameLength(): Int = name.length() } //static methods object Test { def main(args: Array[String]): Unit = { val person1 = new Person("John", 25, BigDecimal(250.00)) val withBonus = person1.calcBonus(BigDecimal(25)) println(withBonus) } } |
Output:
1 2 3 4 |
This is printed when the object is created com.sbthello.Person@330bedb4 275.0 |
Q3. As you can see in the above code we did not use the “new” keyword for the BigDecimal. Just define it as BigDecimal(250.00) or BigDecimal(25). How can we do the same for the Person class?
A3. This can be achieved by creating a “Companion Object” & then defining the apply(…) function in the companion object. A companion object in Scala is a singleton object created in the same file where the class resides with the same name.
For example, “object Person” is defined in the same Scala file Person.scala with the same name as class “Person”.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
package com.sbthello //a class - you create instance of a class, which become objects class Person(name: String, age: Int, salary: BigDecimal) { println("This is printed when the object is created " + this) def calcBonus(bonus: BigDecimal): BigDecimal = salary + bonus def getNameLength(): Int = name.length() } //singleton companion object with static methods object Person { def apply(name: String, age: Int, salary: BigDecimal) = new Person(name, age, salary) } //static methods object Test { def main(args: Array[String]): Unit = { val person1 = Person("John", 25, BigDecimal(250.00)) //same as Person.apply("John", 25, BigDecimal(250.00)) val withBonus = person1.calcBonus(BigDecimal(25)) println(withBonus) } } |
If you want to prevent the above code from using the “new” keyword at all, then define the Person class constructor as “private“.
1 2 3 4 5 |
//.. class Person private(name: String, age: Int, salary: BigDecimal) { //.. |
Q4. How will you fix the print statement in the Person class to print the instance variable values as in “John”, 25, etc as opposed to the object instance value as in “com.sbthello.Person@330bedb4”?
A4. Convert the class to a case class, which gives you toString(..), hashCode(..), equals(..), apply(…) & unapply(..) functions for free as shown below. Companion object is not required.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package com.sbthello //a class - you create instance of a class, which become objects case class Person private(name: String, age: Int, salary: BigDecimal) { println("This is printed when the object is created " + this) def calcBonus(bonus: BigDecimal): BigDecimal = salary + bonus def getNameLength(): Int = name.length() } //static methods object Test { def main(args: Array[String]): Unit = { val person1 = Person("John", 25, BigDecimal(250.00)) // same as Person.apply("John", 25, BigDecimal(250.00)) val withBonus = person1.calcBonus(BigDecimal(25)) println(withBonus) } } |
Output:
1 2 3 4 |
This is printed when the object is created Person(John,25,250.0) 275.0 |
Q5. How do you create multiple constructors in Scala?
A5. Using the this(..).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
package com.sbthello //a class - you create instance of a class, which become objects case class Person private (name: String, age: Int, salary: BigDecimal) { println("This is printed when the object is created " + this) //auxiliary constructor with 2 args def this(name: String, age: Int) = { this(name, age, BigDecimal(0)) } def calcBonus(bonus: BigDecimal): BigDecimal = salary + bonus def getNameLength(): Int = name.length() } //static methods object Test { def main(args: Array[String]): Unit = { val person1 = Person("John", 25, BigDecimal(250.00)) // same as Person.apply("John", 25, BigDecimal(250.00)) val withBonus = person1.calcBonus(BigDecimal(25)) println(withBonus) val person2 = new Person("Peter", 42) //Using the auxiliary constructor with 2 args val withBonus2 = person2.calcBonus(BigDecimal(25)) println(withBonus2) } } |
Output:
1 2 3 4 5 6 |
This is printed when the object is created Person(John,25,250.0) 275.0 This is printed when the object is created Person(Peter,42,0) 25 |
Note that the person2 object was created with the “new” keyword as in new Person(“Peter”, 42) using the auxiliary constructor with 2 args.
Q6. What if you want don’t want to use the “new” keyword every time using an auxiliary constructor?
A6. Create a companion object with the apply(..) function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
package com.sbthello //a class - you create instance of a class, which become objects case class Person private (name: String, age: Int, salary: BigDecimal) { println("This is printed when the object is created " + this) //auxiliary constructor with 2 args def this(name: String, age: Int) = { this(name, age, BigDecimal(0)) } def calcBonus(bonus: BigDecimal): BigDecimal = salary + bonus def getNameLength(): Int = name.length() } object Person { def apply(name: String, age: Int) = new Person(name, age) } //static methods object Test { def main(args: Array[String]): Unit = { val person1 = Person("John", 25, BigDecimal(250.00)) // same as Person.apply("John", 25, BigDecimal(250.00)) val withBonus = person1.calcBonus(BigDecimal(25)) println(withBonus) val person2 = Person("Peter", 42) //Using the auxiliary constructor with 2 args val withBonus2 = person2.calcBonus(BigDecimal(25)) println(withBonus2) } } |
Output:
1 2 3 4 5 6 |
This is printed when the object is created Person(John,25,250.0) 275.0 This is printed when the object is created Person(Peter,42,0) 25 |