Scala OOP: 9 Things You Forgot

DZone 's Guide to

Scala OOP: 9 Things You Forgot

This post holds nine features that Scala has related to object oriented programming that you may not remember — take a look at features like Mixins and mutable case class arguments.

· Java Zone ·
Free Resource

Hello, dear reader! I apologize for the loud title of this article, but you should know that it’s important for me to engage the readers in a discussion. Not so long ago, I decided to systemize my knowledge of object-oriented programming in Scala. That was an awesome idea! And now I want to share all the mini-topics that I underlined as important but that many developers forget about.

Of course, you will find some of it to be very trivial, but I bet you will definitely be surprised by at least with one of these points. Feel free to add your favorite Scala OOP tricks in the comments.

1. Class Constructors

Do you know how to create more than one constructor in a class or in a case class? Scala allows you to do this. You need to use the this keyword.

case class Account(id: String,
                   balance: Double,
                   status: Boolean) {

  def this(id: String) = this(id, 0, false)
  def this(id: String, balance: Double) = this(id, balance, false)
  def this(id: String, status: Boolean) = this(id, 0, status)


val a1 = new Account("a") // Account(a,0.0,false)
val a2 = new Account("b", 100) // Account(b,100.0,false)
val a3 = new Account("b", true) // Account(b,0.0,true)
val a4 = new Account("b", 450, false) // Account(b,450.0,false)

Such constructor declarations can be applied either to common classes or case classes. All constructors created with this keyword are called secondary constructors. Keep in mind that the same result can be achieved with help of a default values declaration.

2. Trait Mixing During Object Initialization

Mixins in Scala are a common practice. You simply create multiple traits and then add them to a class declaration using the with keyword. But what if you want to apply traits dynamically depending on the situation? That's also possible!

class Worker(health: Int) {
  def mineMinerals() = s"Crafting minerals"

trait GasCrafter {
  def mineGas() = "Crafting gas..."

val universalWorker = new Worker(45) with GasCrafter


You can mix as many traits as you want. But as you might guess, it’s very easy to write a code with long mixins and, as a result, lose its readability.

3. Java Developers and Scala OOP

Don’t start a holy war with addicted Java developers about the advantages of Scala OOP. They don’t care how much more concise a Scala code is. For each one of your arguments, they have a separate library: auto-generation of getters and setters, implementation of immutability. etc.
I hope this advice will save a lot of your time

4. Mutable Case Class Arguments

Scala developers know that data implementation starts from case classes. Because Scala propagates immutability, it’s OK that, by default, all the arguments of a case class cannot be overwritten. So when you want to change case class arguments after object creation, use the var keyword:

case class Person(name: String)

val person = Person("Alex")
person.name = "Bob" //Reassignment to val

case class Friend(var name: String)

val friend = Friend("Sam")
friend.name= "Bob" //Ok

friend.name // Bob

So here, absolutely everything is up to you. If you want to ignore Scala recommendations and best practices regarding variable immutability, it’s OK, simply use the var keyword in a case class declaration. But if you want to code in a functional style, the point #6 is for you!

6. Access Modifiers

Scala has a very agile system of access modifiers. Despite the fact that there are fewer than in Java (public is explicitly absent), they are more powerful and give more fine-grained control over class and object fields. In a context of nested classes, inheritance, and packages you can declare fields with such access modifiers:

package myPac

class Foo {

  private[this] val a = 10
  protected val b = 50
  private[free] val c = 15 * commonConstant 

  class FooInner {
    private[Foo] val d = 30

    private[myPac] def doJob() = {}


In the square brackets, we set a precise access level. So instead of the default behavior of the private and protected keywords, we can increase or decrease their effect.

And here is a code for myPac package:

package object myPac {
  val commonConstant = 100

6. “Change” State of Immutable Objects

When you are trying to adhere to functional programming principles, you have to work with immutable values. But this does not mean that you don’t need to change these values. For example, case classes have an auto-generated method copy. It serves for th creation of a new object based on old one. Here is a code sample:

case class Account(id: String, balance: Double, status: Boolean)

def withdraw(amount: Double, acc: Account): Account = {
  acc copy(balance = acc.balance - amount)

def ban(acc: Account): Account = acc copy(status = false)

def toDefault(acc: Account): Account = {
  acc copy(balance = 100, status = true)

val acc1 = Account("v0A0q1", 100, true)

val accAfterWithdraw = withdraw(25, acc1) //Account(v0A0q1,75.0,true)
val bannedAcc = ban(accAfterWithdraw) //Account(v0A0q1,75.0,false)
val restoredToDefaultAcc = toDefault(bannedAcc) //Account(v0A0q1,100.0,true)

With help from the copy method, you can create new objects by changing the value from 0 to N arguments.

7. Apply and Unapply

Frequently, Scala developers call Scala a “data-centric” programming language. In some ways, this is due to case classes and operations and what you can do with them. For each case class, Scala generates two methods — apply and unapply.

Using these methods, you can extract arguments from a case class in a tuple and vice versa.

case class Account(id: String, balance: Double, status: Boolean)

val acc = Account("a01", 10, true)
Account.unapply(acc) // Some((a01,10.0,true))

val dataSet = ("a01",10.0,true)
(Account.apply _).tupled(dataSet) // Account(a01,10.0,true)

You must remember that unapply is an extractor method. Thanks to it, pattern matching can be applied to the object with the appropriate unapply method.

8. Keyword Sealed

During class (trait) creation, you can decorate it with the sealed keyword. This circumstance applies one very important restriction to the class (trait) — it cannot be extended outside of the source file where it was created.

sealed abstract class LegacyDriver {
  def connect(): Unit

class ReactiveDriver extends LegacyDriver {
  override def connect(): Unit = {
    println("Reactive connection...")

class SQLDriver extends LegacyDriver {
  override def connect(): Unit = {
    println("SQL connection...")

In the code snippet above, LegacyDriver is marked with the sealed keyword. It’s OK to extend it directly inside of its source, but its extension isn't allowed outside of it. When is sealed is useful? Well, when you create some particular data hierarchy, you may want to keep some implementations in one place. This is a good use case for sealed.

9. Object and Companion

Scala has its own built-in mechanism for a singleton — object. You can declare an object and then use its members: values and methods. But what is the difference between an object and a companion object in Scala? A companion object is an object with the same name as a class that is created in the same source file.

case class Book(pages: Int, ratio: Int)

object Book {
  def isGoodForJourney(book: Book) = {
    if (book.pages < 200 & book.ratio > 3) true
    else false

val b1 = Book(190, 4)


That’s it! I hope you have discovered something new for yourself, or at least refreshed your memory regarding Scala OOP theory. If you liked the post, please share it on Twitter or Facebook. Next week, I’m going to publish a new article with an analysis of Scala and Java development. 

java ,jvm ,language design ,language features ,oop ,scala

Published at DZone with permission of Alexey Zvolinskiy , DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}