Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 796
Arpit Aggarwal Avatar asked Mar 23 '15 09:03

Arpit Aggarwal


People also ask

What is a sealed trait in Scala?

A sealed trait in scala forces all the case classes/objects that wish to extend it to be in the same source file. In other words, if case class B wishes to extend sealed trait A B has to be defined in the same file where trait A is defined.

How do you extend a trait in Scala?

In Scala, one trait can inherit another trait by using a extends keyword. trait Trait_Name1 extends Trait_Name2 { // Code.. } Traits support multiple inheritance. In Scala, a class can inherit both normal classes or abstract class and traits by using extends keyword before the class name and with keyword before the trait’s name.

What is the difference between traits and inheritance in Scala?

Unlike class inheritance, in which each class must inherit from just one superclass, a class can mix in any number of traits. Traits are used to define object types by specifying the signature of the supported methods. Scala also allows traits to be partially implemented but traits may not have constructor parameters.

Can I extend a sealed trait in a case class?

Case classes can also extend a sealed trait. Thus, objects and case classes can be mixed to create complex hierarchies: sealed trait CelestialBody object CelestialBody { case object Earth extends CelestialBody case object Sun extends CelestialBody case object Moon extends CelestialBody case class Asteroid (name: String) extends CelestialBody }


1 Answers

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. They 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)
like image 71
alcarv Avatar answered Sep 22 '22 06:09

alcarv