Scala - On Classes & Objects
Tags: scala, tutorial, resources
Published: 2018-07-11 15:00:53

---
title: Scala - On Classes & Objects
published: true
description: A beginnerish tutorial on the basics of classes and objects for a Scala beginner.
tags: scala, tutorial, resources
---
I've put together a semi-beginnerish guide for some of the pesky parts of classes and objects in Scala, ideal for someone coming from from languages like JavaScript & Python, and has barely encountered compiled, strongly typed languages. 

I attempt to 
    1. Give the simplest examples
    2. Never ever dare compare Scala to Java
    3. Avoid selling you on functional programming or Scala

Each section builds on the previous one.

### Recommended Resources

These resources are not directly related to this tutorial, but are very useful for learning Scala and functional programming. without making assumptions about your 
[**insert from here:** functional programming/type theory/object oriented programming/category theory/math phd/actor model/Java 8/reactive programming] prowess.  

* [Creative Scala (eBook)](https://underscore.io/training/courses/creative-scala/)
* [Essential Scala (eBook)](https://underscore.io/books/essential-scala/)
* [Tour of Scala](https://docs.scala-lang.org/tour/tour-of-scala.html)
* [Gitter](https://gitter.im/scala/scala) - beginner question welcome!
* [Mostly Adequate Guide to Functional Programming (eBook)](https://github.com/MostlyAdequate/mostly-adequate-guide)
* Haven't watched this, but I'm sure it's great:
[Professor Frisby Introduces Composable Functional Javascript (video course)](https://egghead.io/courses/professor-frisby-introduces-composable-functional-javascript)

### Traits

> Traits are used to share interfaces and fields between classes... Classes and objects can extend traits but traits cannot be instantiated and therefore have no parameters. ([docs](https://docs.scala-lang.org/tour/traits.html))

Traits can have both abstract and concrete methods.

```scala
trait Person {
  // concrete method, can only be overridden by class if it's a def, not a var or val
  def name = "Tim"
  // abstract method, must be implemented in class
  def greeting: String
}

class Tim extends Person {
  def greeting: String = s"Welcome, ${name}"
}

val timClass = new Tim
timClass.greeting
// res0: String = Welcome, Tim
```

You can override `name` in the Person trait:
```scala
class Tim extends Person {
  // override trait name.
  override val name: String = "Mr. Tim"
  def greeting: String = s"Welcome, ${name}"
}

val timClass = new Tim
timClass.greeting
// res0: String = Welcome, Mr. Tim
```
### Plain Objects

An object on its own is simply a way to package together data and functions. Technically, it's a [singleton](https://en.wikipedia.org/wiki/Singleton_pattern) instance of an anonymous class.

```scala
trait Person {
  val name: String
}

object Tim extends Person {
  val name = "Tim"
}

Tim.name
// res0: String = Tim
```

Another example from the App trait:

> The App trait can be used to quickly turn objects into executable programs." ([docs](https://www.scala-lang.org/api/current/scala/App.html))

   The verbose way:
```scala
object HelloWorld {
  def main(args: Array[String]): Unit = {
    val name = args(0)
    println(s"Hello, $name")
  }
}
// "Hello, dude"
```

   Without the boilerplate:
```scala
object HelloWorld extends App {
    val name = args(0)
    println(s"Hello, $name")
}
```
To execute, run `scala HelloWorld.scala dude` from command line.

### Option/Some

Any value that could potentially contain a null/empty value, has an option type, and when assigned, must be wrapped in Some.

```scala
val name: Option[String] = Some("Tim")
name.getOrElse("Anon")
// res0: String = Tim
```

The getOrElse method will provide a default for when name is `None`. It will also reduce `name` from a `Some("Tim")` value, to a plain `"Tim"` value. 

[A nice article](http://blog.originate.com/blog/2014/06/15/idiomatic-scala-your-options-do-not-match/) on idiomatic handling of `Option` values.

> The introduction of Maybe can cause some initial discomfort. Users of Swift and Scala will know what I mean as it's baked right into the core libraries under the guise of Option(al). When pushed to deal with null checks all the time (and there are times we know with absolute certainty the value exists), most people can't help but feel it's a tad laborious. However, with time, it will become second nature and you'll likely appreciate the safety. After all, most of the time it will prevent cut corners and save our hides.

> Writing unsafe software is like taking care to paint each egg with pastels before hurling it into traffic; like building a retirement home with materials warned against by three little pigs. It will do us well to put some safety into our functions and Maybe helps us do just that. ([Mostly Adequate Guide to Functional Programming Ch 8](https://mostly-adequate.gitbooks.io/mostly-adequate-guide/ch08.html#releasing-the-value))

### Pattern Matching

Pattern matching in Scala, [is like a `switch` statement on steroids](https://thecodegeneral.wordpress.com/2012/03/25/switch-statements-on-steroids-scala-pattern-matching/). 

```scala
val name: Option[String] = Some("Bob")

name match {
  // for an exact match on a Tim name
  case Some("Tim") => "Hi, Tim!"

  // for any other Some(value)
  case Some(name) => s"Hi ${name}"

  // default case for any other value
  case _ => "Anonymous has no name!"
}

// res0: String = Hi Bob
```

### Object's apply() and unapply() Methods

The way I think about these functions is that `apply()` is an object's built in constructor, while `unapply()` is how an object deconstructs, which particularly useful for pattern matching. These two functions are mutually exclusive, so you can define one without the other. ([StackOverflow](https://stackoverflow.com/questions/18468786/understand-how-to-use-apply-and-unapply)) Example from [the docs](https://docs.scala-lang.org/tour/extractor-objects.html).

```scala
object Person {
  def apply(name: String) = {
    s"Welcome--$name"
  }
  def unapply(name: String): Option[String] = {
    val nameSplit = name.split("--")
    // we can't be sure the value exists in the object
    if (nameSplit.tail.nonEmpty) Some(s"Goodbye--${nameSplit(1)}")
    else None
  }
}

// using apply() to construct the object
val dudePerson = Person("dude")
println(dudePerson)
// res0: Welcome--dude

// using unapply() to assign a variable
val Person(dudeName) = dudePerson
println(dudeName)
// res1: Goodbye--dude

// using unapply() for pattern matching
val matchTheDude = dudePerson match {
  case Person(name) => name
  case _ => "Goodbye--anonymous dude"
}
println(matchTheDude)
// res2: Goodbye--dude
```

### Class Companion Object

When an object shares the same name with a class, it is commonly referred to as a companion object. It is useful for storing class functionality which isn't tied to an instance of the class (think of them as static or class methods).

For a class/companion object named `Person` with a constructor of `name: String`, the object can access anything from the class by calling `new Person("Tim").value`, while the class can access anything from its object by calling `Person.value`. Even if the values are set to `private`.

```scala

class Person(val name: String) {
  // Person(Tim) instead of the default memory address Person@3018b152
  override def toString = s"Person($name)"
}

object Person {
  // static method to track number of people objects instantiated
  var count = 0

  def apply(name: String): Person = {
    count = count + 1
    // using the Person object as the constructor, allows you to call Person("Tim")         
    // without the need to write "new Person("Tim")"
    new Person(name)
  }

  def unapply(person: Person): Option[String] = Some(person.name)
}

// calling apply() to instantiate the Person class
val bob = Person("Bob")

// our custom toString function
println(bob.toString)
// res0: Person(Bob)

// the apply() increments the count variable for each new Person
val tim = Person("Tim")
Person.count
// res1: 2

// unapply() with pattern matching
val matchTim = tim match {
  case Person(name) => name
  case _ => "Sorry, no match"
}
matchTim
// res2: String = Tim
```

### Case Classes

`case class` is a type of class, which is useful for storing immutable data with minimal boilerplate. `case object` has [similar functionality](https://stackoverflow.com/questions/5270752/difference-between-case-object-and-object), but for a singleton class.

```scala
case class Person(title: Option[String] = None, name: String)

// comes with a companion object apply() method, no need for new Person("Dude")
val dude = Person(name="Dude")

// name parameter is set to an immutable val
dude.name
// res0: String = Dude

// sane toString method, as opposed to Person@721d791f weird hex stuff
dude.toString
// res1: String = Person(None,Dude)

val tim = Person(name="Tim")

// convenient copy method if you only need to change specific values
val timCopy = tim.copy(title=Some("Mr"))
// timCopy: Person = Person(Some(Mr),Tim)

// comes with a companion object unapply() method, useful for pattern matching
timCopy match {
  case Person(title, name) => title
  case _ => "No title"
}
// res2: Some(Mr)

// sane equals method which compares the content of case classes
dude.equals(tim)
// res3: Boolean = false

// class equality is usually done by comparing the memory address of each class 
// instance, that's why you get this weird behavior
class Guy(name: String)

val guy1 = new Guy("guy")
// guy1: Guy = Guy@5f46825d

val guy2 = new Guy("guy")
//guy2: Guy = Guy@17be95d

guy1 == guy2
//res4: Boolean = false
```

### Implicits

A nice example from [here](https://stackoverflow.com/a/10375941/4822174):

```scala
// probably in a library
class Prefixer(val prefix: String)
def addPrefix(s: String)(implicit p: Prefixer) = p.prefix + s

// then probably in your application
implicit val myImplicitPrefixer = new Prefixer("***")
addPrefix("abc")  // returns "***abc"
```

The [Play Framework controllers](https://www.playframework.com/documentation/2.6.x/ScalaActions) use implicits, so that any function call from an `Action` will gain access to the http `request` variable:

```scala
def action = Action { implicit request =>
   anotherMethod("Some para value")
   Ok("Got request [" + request + "]")
 }

def anotherMethod(p: String)(implicit request: Request[_]) = {
 // do something that needs access to the request
 }
```

`implicit` comes in handy when converting case classes to and from Json with the [Play Json library](https://www.playframework.com/documentation/2.6.x/ScalaJson). This is simple way to get type-safe JSON when creating an API:

```scala
import play.api.libs.json.Json
case class Totals(
                   subTotal: Double = 0,
                   estimatedShippingAndInsurance: Double = 0,
                   estimatedTax: Option[Double] = Some(0),
                   orderTotal: Double = 0
                 )
// withDefaultValues is required if you want your case class defaults to be applied // to the Json conversion
object Totals { implicit val writeTotals = Json.using[Json.WithDefaultValues].format[Totals] }
```

### Class Structuring

In object oriented programming, [we make a distinction](https://stackoverflow.com/questions/2218937/has-a-is-a-terminology-in-object-oriented-language) between _is-a_ and _has-a_. _is-a_ is a candidate for inheritance.

A Product _has-a_ `salePrice` _and_ a `regularPrice`:

```scala
trait Product {
  val salePrice: Double
  val regularPrice: Double
}
```
A computer _is-a_ product in a store:

```scala
case class Computer(
                     salePrice: Double,
                     regularPrice: Double,
                     processor: String,
                     operatingSystem: String
                   ) extends Product
```

Clothes _is-a_ Product as well:

```scala
case class Clothes(
                     salePrice: Double,
                     regularPrice: Double,
                     size: Int,
                     material: String
                   ) extends Product
```

Another point to consider, Product is of type Computer _or_ Clothes.

A common pattern for _is-or_ (from Essential Scala):

```scala
sealed trait TrafficLight {
// pattern matching on case objects
  def next: TrafficLight = this match {
    case Red => Green
    case Green => Yellow
    case Yellow => Red
  }
}
final case object Red extends TrafficLight
final case object Green extends TrafficLight
final case object Yellow extends TrafficLight

val myLight = Red.next
// res0: TrafficLight = Green
myLight.next
// res0: TrafficLight = Yellow
myLight.next.next
// res1: TrafficLight = Red
```

`sealed trait` is used to tell the compiler to only expect TrafficLight of types Red, Green and Yellow. If we were to leave out Yellow while pattern matching, the compiler would complain that `match may not be exhaustive`. `final` is to forbid anyone form extending the Red, Green and Yellow classes.