Arpit Arpit - 7 months ago 21
Java Question

Class, Object, Trait, Sealed Trait in Scala

I am from

OOP
background and and want to clear my idea about
Object
,
Classes
,
Trait
,
Sealed Trait
and
Case Classes
in
Scala
, I am writing below what I understand about it so far:

We create
Object
, when we want to code some utility functions inside it and we can access it directly, without using "new" keyword like "Static" classes in Java.

We create
Classes
, when we are coding for verb means an object and it's behavior encapsulated same as we code for classes in Java and we instantiate it using "new" keyword.

We create
Trait
when we want to code same as Abstract classes in
Java
.

We create
Sealed Trait
when we want to achieve functionality as same Enum in Java.

We create
Case classes
when we can expect that this class can be used for pattern matching in future similar to instanceOf in Java.

Is my understanding correct about all these?

Answer

You're more or less right about most of the facts you've stated if you look into them with an OOP eye. But we have more to them.

Object

Objects in Scala can be seen from a Functional Programming perspective as modules. The do serve the purpose of aggregating similar kinded functions that you have called "utility functions". But they have additional meanings as well.

An object can be seen as a singleton object, as you can have an object that inherits a particular trait or class.

trait Bird
object Duck extends Bird

You also have the concept of companion object. That is an object that have module functions related to that class and you can even refer private members of the object from the class.

class Dog {
  def eat(food: Food) = Dog.preferredFoods.contains(food)
}

object Dog {
  private val preferredFoods = List(Ribeye, DogFood, Banana)
  def walk(dog: Dog) = ???
}

Class

You are right about classes. They relate quite close to the Java concept.

Trait

One way to view a trait in Scala is as an abstract class. But note you can also have an abstract class in Scala, with the same behaviour as in Java. So what's the difference?

As pointed in the comment, several traits can be mixed in together.

Also traits can be regarded as a Java interface if it's completely abstract, that is all methods are abstract as with Java. In fact, if you're targeting interop with Java, that's the way to declare an interface.

A sealed trait is just a way to tell the compiler that you won't have any classes or other traits that inherit this one except for the ones in the same file. This serves the purpose of pattern matching as you pointed out about case classes, so the compiler is able to tell if the pattern match is exhaustive with a warning. But also note the Scala has enum.

Case class

Case classes can be used with a sealed trait for the purpose of pattern matching. But a case class is more like a "value class". The case makes the compiler generate a bunch of boilerplate code so you don't have to.

You have an automatic "companion object" so you can instantiate object without the new, with the auto generated apply function.

You have automatic hashCode, equals, toString and copy implementations. And you have automatic vals for all constructor's parameters.

scala> case class Room(area: Int)
defined class Room

scala> var r = Room(16)
r: Room = Room(16)

scala> r.hashCode
res2: Int = 1313771839

scala> r == Room(16)
res3: Boolean = true

scala> r == Room(15)
res4: Boolean = false

scala> r.toString
res5: String = Room(16)

scala> r.area
res6: Int = 16

scala> case class Point(x: Int, y: Int)
defined class Point

scala> val p = Point(1, 1)
p: Point = Point(1,1)

scala> val p1 = p.copy(y = 0)
p1: Point = Point(1,0)
Comments