7 minutes read

Sometimes, project code uses values or functions that are not linked to any classes. These can be global constants or functions that perform a transformation of data. But you can't simply define val and def in an empty Scala file. For this reason, there is an implementation of a singleton pattern in Scala known as an object. Let's see how objects help store values and functions, and how to initialize them!

Constants and functions

Object definition is similar to the class definition, but they can't take any parameters. Because you can’t instantiate an object with the new keyword, there is no way to pass parameters to it.

object ErrorCodes:
  val BadRequest: Int = 400
  val NotFound: Int = 404

  def allErrors: Set[Int] = Set(BadRequest, NotFound)

Unlike a class, an object's instance is created once, when it is referenced, and the next calls from code will refer to this instance. It means that any object initialization logic will be invoked once.

object ErrorCodes:
  ...
  // configuration will be accessed only once during initialization of ErrorCodes
  val SpecialError: Int = getGlobalConfig().get("errors.special-error-code")

So, objects are good to use as a hold of methods and constants that will be available without having to instantiate an instance of some class first. You can import and use all members of an object in any place in the code as follows:

def onParsingFailure(request: Request): ServerError = {
  import ErrorCodes.*

  ServerError(path = request.path, statusCode = BadRequest)
}

Namespace

Besides values and functions, the creation of other entities is also available. Those entities will be under object scope. For example, let's define the message of each error, since only the code of the error is not enough:

object Errors:
  class ParsingError(val message: String)

Here you can use the class by importing them or using the object name prefix:

val error: Errors.ParsingError = Errors.ParsingError("Wrong Json!")

Objects are not exceptions. They can also be implemented inside other objects, especially objects that are common for the whole program and don't take any arguments:

object Errors:
  class ParsingError(val message: String)

  object InternalServerError:
    val message: String = "Oh, something broke, sorry"

Moreover, each object has its own type, which allows you to use them as values:

import Errors.*

// to get the type of an object, you need to use .type
val error: InternalServerError.type = InternalServerError

In this case, we can use all the values of the object through a new variable:

error.message // Oh, something broke, sorry

Singleton instance

An object can inherit a trait, as well as a class. This means you can build hierarchies of entities, some of which will have only one value:

object Errors:
  trait Error: 
    def description: String

  class ParsingError(val message: String) extends Error
    val description: String = "an error was detected during json parsing"

  object InternalServerError extends Error:
    // it is required to define all methods as in the class 
    val description: String = "internal error, please repeat the request later"

Package object

If you add the keyword package to an object, all members inside that object will be available to code within that package. Each package is allowed to have one package object. You should put your package object in a separate file called package.scala, in the directory that it corresponds to. This makes it easier to work with constants and functions that are common to a particular application package.

// src/main/scala/myapp/errors/package.scala

package object errors {
  val BadRequest: Int = 400
  val NotFound: Int = 404
}

Conclusion

To sum up, each object has one instance of itself and uses it as space where you can implement additional logic. After implementing some logic, you can put that code into a package that you need by using a package object. An object can inherit a trait or a class if you often reuse the same part of code.

3 learners liked this piece of theory. 0 didn't like it. What about you?
Report a typo