Scala - Classes & Objects



This chapter takes you through how to use classes and objects in Scala programming. A class is a blueprint for objects. Once you define a class, you can create objects from the class blueprint with the keyword new. Through the object you can use all functionalities of the defined class.

The following diagram demonstrates the class and object by taking an example of class student, which contains the member variables (name and roll no) and member methods (setName() and setRollNo()). Finally all are members of the class. Class is a blue print and objects are real here. In the following diagram, Student is a class and Harini, John, and Maria are the objects of Student class, those are having name and roll-number.

Scala Classes and Objects

Basic Class

Following is a simple syntax to define a basic class in Scala. This class defines two variables x and y and a method: move, which does not return a value. Class variables are called, fields of the class and methods are called class methods.

The class name works as a class constructor which can take a number of parameters. The above code defines two constructor arguments, xc and yc; they are both visible in the whole body of the class.

Syntax

class Point(xc: Int, yc: Int) {
   var x: Int = xc
   var y: Int = yc

   def move(dx: Int, dy: Int) {
      x = x + dx
      y = y + dy
      println ("Point x location : " + x);
      println ("Point y location : " + y);
   }
}

As mentioned earlier in this chapter, you can create objects using a keyword new and then you can access class fields and methods as shown below in the example −

Example

import java.io._

class Point(val xc: Int, val yc: Int) {
   var x: Int = xc
   var y: Int = yc
   
   def move(dx: Int, dy: Int) {
      x = x + dx
      y = y + dy
      println ("Point x location : " + x);
      println ("Point y location : " + y);
   }
}

object Demo {
   def main(args: Array[String]) {
      val pt = new Point(10, 20);

      // Move to a new location
      pt.move(10, 10);
   }
}

Save the above program in Demo.scala. The following commands are used to compile and execute this program.

Command

\>scalac Demo.scala
\>scala Demo

Output

Point x location : 20
Point y location : 30

Extending a Class

You can extend a base Scala class and you can design an inherited class in the same way you do it in Java (use extends key word), but there are two restrictions: method overriding requires the override keyword, and only the primary constructor can pass parameters to the base constructor. Let us extend our above class and add one more class method.

Example

Let us take an example of two classes Point class (as same example as above) and Location class is inherited class using extends keyword. Such an extends clause has two effects: it makes Location class inherit all non-private members from Point class, and it makes the type Location a subtype of the type Point class. So here the Point class is called superclass and the class Location is called subclass. Extending a class and inheriting all the features of a parent class is called inheritance but Scala allows the inheritance from just one class only.

Note − Methods move() method in Point class and move() method in Location class do not override the corresponding definitions of move since they are different definitions (for example, the former take two arguments while the latter take three arguments).

Try the following example program to implement inheritance.

import java.io._

class Point(val xc: Int, val yc: Int) {
   var x: Int = xc
   var y: Int = yc
   
   def move(dx: Int, dy: Int) {
      x = x + dx
      y = y + dy
      println ("Point x location : " + x);
      println ("Point y location : " + y);
   }
}

class Location(override val xc: Int, override val yc: Int,
   val zc :Int) extends Point(xc, yc){
   var z: Int = zc

   def move(dx: Int, dy: Int, dz: Int) {
      x = x + dx
      y = y + dy
      z = z + dz
      println ("Point x location : " + x);
      println ("Point y location : " + y);
      println ("Point z location : " + z);
   }
}

object Demo {
   def main(args: Array[String]) {
      val loc = new Location(10, 20, 15);

      // Move to a new location
      loc.move(10, 10, 5);
   }
}

Save the above program in Demo.scala. The following commands are used to compile and execute this program.

Command

\>scalac Demo.scala
\>scala Demo

Output

Point x location : 20
Point y location : 30
Point z location : 20

Implicit Classes

Implicit classes allow implicit conversations with classs primary constructor when the class is in scope. Implicit class is a class marked with implicit keyword. This feature is introduced in Scala 2.10.

Syntax − The following is the syntax for implicit classes. Here implicit class is always in the object scope where all method definitions are allowed because implicit class cannot be a top level class.

Syntax

object <object name> {
   implicit class <class name>(<Variable>: Data type) {
      def <method>(): Unit =
   }
}

Example

Let us take an example of an implicit class named IntTimes with the method times(). It means the times () contain a loop transaction that will execute the given statement in number of times that we give. Let us assume the given statement is 4 times println (Hello) means the println (Hello) statement will execute 4 times.

The following is the program for the given example. In this example two object classes are used (Run and Demo) so that we have to save those two classes in different files with their respective names as follows.

Run.scala − Save the following program in Run.scala.

object Run {
   implicit class IntTimes(x: Int) {
      def times [A](f: =>A): Unit = {
         def loop(current: Int): Unit =
         
         if(current > 0){
            f
            loop(current - 1)
         }
         loop(x)
      }
   }
}

Demo.scala − Save the following program in Demo.scala.

import Run._

object Demo {
   def main(args: Array[String]) {
      4 times println("hello")
   }
}

The following commands are used to compile and execute these two programs.

Command

\>scalac Run.scala
\>scalac Demo.scala
\>scala Demo

Output

Hello
Hello
Hello
Hello

Note

  • Implicit classes must be defined inside another class/object/trait (not in top level).

  • Implicit classes may only take one non implicit argument in their constructor.

  • Implicit classes may not be any method, member or object in scope with the same name as the implicit class.

Case Classes

Case classes in Scala are a special type of class that are immutable by default and come with various utility methods. For example: apply, unapply, copy, toString, equals, and hashCode. These classes are used in pattern matching. So you can work with data by providing a concise and immutable representation.

The following is the syntax for defining a case class. Here, a case class is defined with the case class keyword followed by the class name and its parameters.

Syntax

case class <ClassName>(<parameter1>: <Type1>, <parameter2>: <Type2>, ...)

Example

Let us take an example of a case class named Point with two parameters x and y. This case class provides a simple and immutable representation of a point in a 2D space. The copy method allows creating a new instance with modified values.

The following is the program for the given example. This example defines and demonstrates the usage of the Point case class.

Run.scala − Save the following program in Run.scala.

case class Point(x: Int, y: Int)

object Demo {
  def main(args: Array[String]) {
    val pt1 = Point(10, 20)        // Creating an instance of Point
    val pt2 = pt1.copy(y = 30)     // Copying pt1 and modifying the y value
    println(pt1)                   // Printing the original point
    println(pt2)                   // Printing the copied point with modified y
  }
}

The following commands are used to compile and execute this program.

Command

\>scalac Run.scala
\>scalac Demo.scala
\>scala Demo

Output

Point(10, 20)
Point(10, 30)

Note

  • Case classes are immutable by default. Once an instance is created, it cannot be modified.
  • Case classes automatically provide equals and hashCode methods. So suitable for use in collections that rely on these methods, like sets and maps.
  • The copy method in case classes can create new instances with modified fields without altering the original instance.
  • Pattern matching works with case classes.

Abstract Classes

Abstract classes in Scala are similar to traits but can have constructor parameters. Abstract classes are used when you want to create base classes that should not be instantiated directly but can be extended by other classes. An abstract class can contain both abstract and non-abstract methods.

Syntax − The following is the syntax for defining an abstract class. Here, the abstract class is defined with the abstract class keyword followed by the class name and its parameters.

Syntax

abstract class <ClassName>(<parameter1>: <Type1>, <parameter2>: <Type2>, ...) {
  def <abstractMethod>(<parameters>): <ReturnType> // Abstract method
  def <nonAbstractMethod>(<parameters>): <ReturnType> = {
    // Method body
}

Example

Let us take an example of an abstract class named Shape with an abstract method area. This abstract class serves as a base class for different types of shapes, each providing its own implementation of the area method.

The following is the program for the given example. This example defines and demonstrates the usage of the Shape abstract class and its subclass Circle.

Run.scala − Save the following program in Run.scala.

abstract class Shape {
  def area: Double // Abstract method
}

class Circle(val radius: Double) extends Shape {
  def area: Double = Math.PI * radius * radius // Implementation of abstract method
}

object Demo {
  def main(args: Array[String]) {
    val circle = new Circle(5) // Creating an instance of Circle
    println(s"Area of the circle: ${circle.area}") // Printing the area of the circle
  }
}

The following commands are used to compile and execute this program.

Command

\>scalac Run.scala
\>scalac Demo.scala
\>scala Demo

Output

Area of the circle: 78.53981633974483

Note

  • Abstract classes can have constructor parameters, unlike traits.
  • Abstract classes can contain both abstract methods (without an implementation) and non-abstract methods (with an implementation).
  • Subclasses extending an abstract class must provide implementations for all abstract methods.
  • Abstract classes cannot be instantiated directly; they can only be instantiated through their subclasses.

Singleton Objects

Scala is more object-oriented than Java because in Scala, we cannot have static members. Instead, Scala has singleton objects. A singleton is a class that can have only one instance, i.e., Object. You create singleton using the keyword object instead of class keyword. Since you can't instantiate a singleton object, you can't pass parameters to the primary constructor. You already have seen all the examples using singleton objects where you called Scala's main method.

Following is the same example program to implement singleton.

Example

import java.io._

class Point(val xc: Int, val yc: Int) {
   var x: Int = xc
   var y: Int = yc
   
   def move(dx: Int, dy: Int) {
      x = x &plus; dx
      y = y &plus; dy
   }
}

object Demo {
   def main(args: Array[String]) {
      val point = new Point(10, 20)
      printPoint

      def printPoint{
         println ("Point x location : " &plus; point.x);
         println ("Point y location : " &plus; point.y);
      }
   }
}

Save the above program in Demo.scala. The following commands are used to compile and execute this program.

Command

\>scalac Demo.scala
\>scala Demo

Output

Point x location : 10
Point y location : 20
Advertisements