Classes: Members and Accessor Methods (Getters)

Classes can have members, which are fields and methods.

Here’s an OOP example:

import scala.collection.mutable.ArrayBuffer

class Pizza(
    val crustSize: CrustSize = Medium,
    val crustType: CrustType = Regular
):

    // a private field
    private val toppings = ArrayBuffer[Topping]()

    // members inside the class
    def addTopping(t: Topping): Unit = 
        toppings += t

    def addToppings(ts: Topping*): Unit = 
        toppings.appendAll(ts)

    def removeAllToppings(): Unit =
        toppings.clear()

    override def toString = s"""
        |A $crustSize pizza with a $crustType crust.
        |Toppings:     ${p.toppings.mkString(", ")}""".stripMargin

end Pizza

Fields in a class

To demonstrate field in a class, here are a few enums (enumerations) to help us get started:

enum CrustSize:
    case Small, Medium, Large

enum CrustType:
   case Thin, Thick, Regular

enum Topping:
    case Cheese, Mushrooms, GreenPeppers, Olives

import CrustSize.*
import CrustType.*
import Topping.*

Given those enums, you can create a Pizza class like this:

// [1] can do this
class Pizza(
    var crustSize: CrustSize,
    var crustType: CrustType,
    val toppings: ArrayBuffer[Topping]
)

But to demonstrate fields, you can also use fields for those values:

// [2] can also do this
import scala.collection.mutable.ArrayBuffer
class Pizza:
    var crustSize = Medium
    var crustType = Regular
    val toppings = ArrayBuffer[Topping]()

Given that second class, this example shows how to create a pizza and update the values of those fields:

val p = Pizza()
p.crustSize = Large
p.crustType = Thin
p.toppings ++= Seq(Cheese, Mushrooms)

Note that I mutate the ArrayBuffer directly there

Member visibility

You can also control the possibility of members. They are public by default, and you can make them private or protected.

A good question in the following example is, “Should toppings be publicly accessible?”

import scala.collection.mutable.ArrayBuffer
class Pizza:
    var crustSize = Medium
    var crustType = Regular
    private val toppings = ArrayBuffer[Topping]()
    -------

That is, do you want other people to have direct access to your ArrayBuffer? For me, the answer is no, so we make toppings private.

The fact that toppings is implemented as an ArrayBuffer is an implementation detail that we don’t want to leak out to people who use our class.

Methods in a class

Scala classes can also have methods, as shown in this example:

import scala.collection.mutable.ArrayBuffer

class Pizza(
    val crustSize: CrustSize = Medium,
    val crustType: CrustType = Regular
):

    private val toppings = Seq[ArrayBuffer]()

    def addTopping(t: Topping): Unit = 
        toppings += t

    def addToppings(ts: Topping*): Unit = 
        toppings.appendAll(ts)

    def removeAllToppings(): Unit =
        toppings.clear()

    override def toString = s"""
        |A $crustSize pizza with a $crustType crust.
        |Toppings:     ${p.toppings.mkString(", ")}""".stripMargin

end Pizza

You can then create a Pizza:

// either of these will work
val p = Pizza()
val p = Pizza(Medium, Regular)

Update the values in its fields:

p.crustSize = Large
p.crustType = Thin
p.toppings

And call those methods:

p.addTopping(Cheese)
p.addToppings(Mushrooms, Olives)

p.removeAllToppings()