Published 2014-01-02.
Last modified 2016-03-02.
Time to read: 2 minutes.
Singletons and companion objects are explored in this lecture.
The sample code for this lecture can be found in
courseNotes/
.

Singletons
Singletons provide an equivalent to static methods as found in Java, C++ and C#. However, singletons go beyond this.
- A singleton can inherit methods from other classes and/or traits, which cannot be done with Java static methods.
- A singleton can be passed as a parameter, perhaps via an inherited interface.
- A singleton can exist within the scope of a surrounding class or method, just as Java can have inner classes.
Scala has the reserved word object
which is used to define a singleton object.
Let’s see an object in action.
To do this, we’ll start the sbt console
, and import all of the classes and traits defined in the animals
package, including Frog5
.
$ sbt console [info] Loading global plugins from /home/mslinn/.sbt/0.13/plugins [info] Done updating. [info] Loading project definition from /var/work/course_scala_intro_code/courseNotes/project [info] Done updating. [info] Set current project to IntroScalaCourse (in build file:/var/work/course_scala_intro_code/courseNotes/) [info] Starting scala interpreter... scala> import animals._ import animals._
Now we can define an object called OnlyOne
.
Objects are often declared with the first letter in upper case, but exceptions are common.
scala> object OnlyOne extends Frog5(canSwim=true, numLegs=2, breathesAir=true) defined object OnlyOne
scala> %}def doSomething(frog: Frog5): Unit = println(frog) doSomething: (frog: Animals.Frog5)Unit
scala> %}doSomething(OnlyOne) canSwim: true; 2 legs; breathesAir: true
Companion Objects and the REPL

Companion objects are singletons associated with a class in which you can define fields, methods, inner objects, inner classes and inner traits. In order for companion objects to have their magic activated, they must have the same name as the class they are associated with, and must be defined in the same file as a class of the same name.
The REPL’s paste mode was designed to allow companion objects to be defined with companion classes.
For example, let’s redefine Frog5
as Frog6
and give it a companion object.
scala> :paste // Entering paste mode (ctrl-D to finish)
scala> class Frog6(val canSwim: Boolean, numLegs: Int, breathesAir: Boolean) { override def toString = s"canSwim: $canSwim; $numLegs legs; breathesAir: $breathesAir" }
object Frog6 { def apply(canSwim: Boolean=true, numLegs: Int=4, breathesAir: Boolean=true) = new Frog6(canSwim, numLegs, breathesAir) } ^D // Exiting paste mode, now interpreting.
defined class Frog6 defined object Frog6
If both of these definitions were placed in the same file then Frog6
would be a companion object of the Frog6
class, and the Frog6
class would be a companion class to the Frog6
object.
In Scala, methods called apply
are default methods, and are often used as factories.
Because they are default methods, you don’t have to use their name when invoking them.
Notice that the parameters for the companion object’s apply
method are the same as the parameters to the primary constructor for the class.
This is very common.
For example, you could create a new Frog6
instance with either of the following statements; both are equivalent.
scala> val frog6a = Frog6(canSwim=true) frog6a: Frog6 = canSwim: true; 4 legs; breathesAir: true
scala> %}val frog6b = Frog6.apply(canSwim=true) frog6b: Frog6 = canSwim: true; 4 legs; breathesAir: true
Notice that the apply
method that I defined has default values for all parameters, so the default values of numLegs
and breathesAir
were used because those parameters were not specified.
Also notice that when a companion object is defined, its name (Frog6
) refers to the singleton instance.
BTW, Ammonite (discussed in the SBT Global Setup and
SBT Project Setup lectures) has a
block input mode,
which is similar to the Scala REPL’s :paste
mode.
Importing Methods and Properties
If you want the methods and properties defined in the companion object to be available in the companion class, you must fully qualify them or import them.
scala> :paste // Entering paste mode (ctrl-D to finish)
scala> class Frog7(val canSwim: Boolean, numLegs: Int, breathesAir: Boolean) { import Frog7.croak
def makeNoise = croak(3)
override def toString = s"canSwim: $canSwim; $numLegs legs; breathesAir: $breathesAir" }
object Frog7 { def apply(canSwim: Boolean=true, numLegs: Int=4, breathesAir: Boolean=true) = new Frog7(canSwim, numLegs, breathesAir)
def croak(times: Int): String = ("Croak " * times).trim } // Entering paste mode (ctrl-D to finish)
// Exiting paste mode, now interpreting.
defined class Frog7 defined module Frog7
scala> Frog7(canSwim=true, 4, breathesAir=true).makeNoise // Entering paste mode (ctrl-D to finish)
res0: String = "Croak Croak Croak"
© Copyright 1994-2024 Michael Slinn. All rights reserved.
If you would like to request to use this copyright-protected work in any manner,
please send an email.
This website was made using Jekyll and Mike Slinn’s Jekyll Plugins.