Data structures and classes in Scala
Data structures
We saw several built-in data structures in Python: lists, hashtables, and sets. Scala has analogues of all three:
scala> val lyrics = List("Happy", "birthday", "to") scala> val songs = Map("Beatles" -> List("Yellow Sub", "Help"), "Britney" -> List("Toxic", "Oops")) scala> val genres = Set("country", "rock", "rap") scala> lyrics(2) "to" scala> songs("Beatles")(1) "Help" scala> genres.contains("bluegrass") false scala> genres("bluegrass") // same thing as above! false
All three work pretty much like their counterparts in Python, with one big difference: all three are immutable. This means that once we’ve built a List, Map, or Set, we can’t change its contents! So we can do operations like this:
scala> lyrics :+ "you" List("Happy", "birthday", "to", "you") scala> songs :+ ("Cardi B" -> List("I Like It")) Map("Beatles" -> List("Yellow Sub", "Help"), "Britney" -> List("Toxic", "Oops"), "Cardi B" -> List("I Like It")) scala> genres + "bluegrass" Set("country", "rock", "rap", "bluegrass")
But we can’t do operations like this:
scala> lyrics(0) = "Sad" ERROR scala> songs("Beatles") = List("Sgt Pepper") ERROR scala> genres.add("folk") ERROR
In general, when you’re programming in Scala you’ll use these immutable versions of data structures. However, Scala does also have mutable data structures:
scala> val lyrics = Array("Twinkle", "twinkle", "little", "star") scala> lyrics(3) = "fish" scala> val numbers = scala.collection.mutable.Map("one" -> 1, "two" -> 2) scala> numbers("three") = 3 scala> numbers("three") 3 scala> val cities = scala.collection.mutable.Set("Cranston", "Central Falls") scala> towns.add("Newport")
var
, val
, mutability, and immutability
Did you notice something surprising about that last code block? I said that
val
means you can’t change the value of a name, but we sure seem to be
changing lyrics
, numbers
, and cities
! What’s going on? Can we think about
what this means in terms of the program dictionary and memory?
If I define a name x
as a val
, I can’t change the value of x
in the
program dictionary. But if x
is mapped to a location in memory–say, loc
6
–I can change loc 6
(for instance, adding an entry to a mutable Map
)
without changing the entry for x
in the program dictionary!
See the lecture capture for more details about this distinction.
Classes and objects in Scala
Let’s translate one more program from Python to Scala.
class DJData: def __init__(self, dj_name: str): self.dj_name = dj_name self.num_callers = 0 self.queue = [] def request(self, caller: str, song: str) -> str: self.queue.append(song) self.num_callers += 1 if self.num_callers % 1000 == 0: return "Congrats, " + caller + "! You get a prize from " + dj_name + "!" else: return "Cool, " + caller
We can translate this to Scala as follows:
class DJData(val djName: String) { var numCallers: Int = 0 var queue: List[String] = List() def request(caller: String, song: String): String = { queue = queue :+ song numCallers += 1 if (numCallers % 1000 == 0) { "Congrats, " + caller + "! You get a prize from " + djName + "!" } else { "Cool, " + caller } } }
There are a few important differences above:
- In Scala, we don’t write out a class’s constructor (i.e.,
__init__
in Python). Instead, we put any fields we want to initialize from outside the class into the first line. - Methods don’t take a
self
argument - Inside a method, we don’t need to write
self.queue
: we can just writequeue
.
We can make an instance of this class and experiment with its functionality in the REPL:
scala> val djd = new DJData("DJ Doug") scala> djd.request("Alex", "Stairway to Heaven") "Cool, Alex" scala> djd.queue List("Stairway to Heaven")