A handshake with Scala

Author

Thadryan

Published

July 20, 2018

Scala is a JVM language that seeks to marry functional and object-oriented programming styles. It was was Designed by Martin Odersky and first appeared in 2004. While I think many projects that aspire to “best of both worlds” status end up ugly and chimeric, my explorations with Scala have revealed a really thoughtful and lovely creation that elegantly merges different paradigms. While it isn’t one of the top-tier languages for for production code job hunting (think Java, C++, Python, JavaScript, etc), it made the GitHub top 15 list for most common languages recently. I suspect much of this is because it’s becoming popular as a language for data science as a happy medium language between the breezy-to-write-but-relatively-slow Python and the incumbent production veteran Java that is faster but comes with a notoriously verbose syntax (still very much worth learning though!). Scala aims to be approachable and quick to develop as well as fast (some tests show it performing at Java speed or better), thus avoiding the need to “productionize” slower, exploratory code if a project grows (The name “Scala” is a shortening of the “Scalable Language”, after all). Nobody is going to be putting Java out of business any time soon (just ask the flashier start-up favorite Ruby, but Scala joins Python, Java, and R as a helpful tool for data and general purpose coding. After spending a good amount of time with the Scala home page, “Scala for the Impatient”by Cay S. Horstmann, and Bruce Eckel’s classic “Thinking in Java”, I opted to create an overview for my own edification and for some people I know who are newcomers to the language. Happy Hacking.

// hello world in Scala 
object helloWorld {
    def main(args: Array[String]): Unit = {
        println("Hello World")       
    }
}
defined object helloWorld

In Scala, a program takes place in a “singleton object”. This is an object of which only one iteration can exist. This is slightly different than Java, where it would be written as “class helloWorld {”.

Next we see a “main” method defined like in Java. Also like Java, this function takes an Array of Strings as an argument ( args: Array[String]) ). The more unusual part is “Unit”. This is the Scala’s version of “void”, which means that the function doesn’t return anything (it just executes the code inside it).

After that, there is a println() call that will look familiar to Java coders that prints the message.

Because we are using a notebook, we can write snippets of code outside an object like this, but keep in mind if we were writing a program in a more typical format it would need to be inside that object.

From now on, we can just write:

println("Hello World")
Hello World

Declaration

In Scala, variables are declared as “Val” or “Var”, for “Value” or “Variable”. A item declared as a “Val” cannot be changed (it is said to be “immutable”, where as a “Var” can (it is “mutable”). This a key part of Scala’s functional programming background.

// mutable 
var x = 1

// immutable 
val y = 2

This means we could change x but we could not change y:

// this is perfectly legal 
x = x + 1
println(x)

// this would kick a "reassignment to val" error 
// y = y + 1
2

The next line of code demonstrates that Scala’s type declarations are “backwards” compared to more traditional languages. Scala would say “val age: Int = 10” not “Int age = 10”. According to Cay S. Horstmann, the author or “Scala for the Impatient”, this makes it easier to read the code when large, complicated functions are used. While this isn’t typical, Scala’s designers aren’t the only ones who think so:

https://blog.golang.org/gos-declaration-syntax

It takes a bit of getting used to but is not a huge deal, and the clarity pays off later. I think of this as the programming equivalent of Romance languages that say “The dress red” instead of “The red dress”.

val nameDeclared: String = "Charli Declared" // not "val String: name = "Charli"
nameDeclared: String = "Charli Declared"

Also, Scala has type inference, so we could use this shorthand:

// no type declaration
val nameInferred = "Charli Inferred"
println(nameDeclared + " " + nameInferred)
Charli Declared Charli Infered
nameInffered: String = "Charli Infered"

Types

Given it’s descent from Java and it’s intent to build large systems securely, Scala uses strong, static typing.

val wholeNumber: Int = 10

val decimalNumber: Double = 10.1

// specify float 
val floatDecimalNumber: Float = 10.1f

val bigNumber: Long = 100000000

// note double quotes 
val string: String = "Heya"

// note single quotes 
val aLetter: Char = 'A'

val answer: Boolean = true

// will be convere
val doubleOverridesInt = wholeNumber + decimalNumber
wholeNumber: Int = 10
decimalNumber: Double = 10.1
floatDecimalNumber: Float = 10.1F
bigNumber: Long = 100000000L
string: String = "Heya"
aLetter: Char = 'A'
answer: Boolean = true
doubleOverridesInt: Double = 20.1

Scala types are built as classes, so it offers some convenience methods for conversion:

100.toString
res60: String = "100"

Arithmetic Operators

Arithmetic operators are fairly traditional in Scala:

Exponents are handled via Scala’s math library.

var x: Int = 10

// call the power function from 'math'
scala.math.pow(x,2)

Strings + Iteration

Let’s look at some simple string manipulations.

val name: String = "Jade"

// println at an index
println(name(0))
J
name: String = "Jade"

Note that the () is used, not the traditional []. This is due to Scala’s functional outlook, looking at the String as a function that maps an element to the String location of that element.

Let’s change the case. Notice there are no () at the end of this method calls. If the method has parenthesis, they are optional if arguments are not being passed (if the method is declared with no parenthesis, however, you must follow suit).

// change to upper case
name.toUpperCase

// to lower 
name.toLowerCase()
res63_0: String = "JADE"
res63_1: String = "jade"

Iterating over a string reveals some interesting traits of Scala. The String class has a “foreach” method, which, paired with the “default variable” and a bit of syntax, allows for iteration.

// foreach is a method of the String name 
name.foreach{ letter =>
    println(letter)
}
J
a
d
e

We can also use and index. It has an R-like arrow assignment to the i, and then an obvious, English-like syntax for “0 until the end of the length” of the name.

// for i in until the end of the length 
for(i <- 0 until name.length) {
    println("Letter at index " + i + " is " + name(i))
}
Letter at index 0 is J
Letter at index 1 is a
Letter at index 2 is d
Letter at index 3 is e

We can also use and index. It has an R-like arrow assignment to the i, and then an obvious, English-like syntax for “0 until the end of the length” of the name.

for(i <- name.indices) {
    println(name(i))
}
J
a
d
e

In Scala 2.1+ you can interpolate strings with the s + $ syntax

println(s"Hello there, my name is $name")
Hello there, my name is Jade

This also works with floats, using a C-style syntax specifying the number of decimals:

val height: Double = 1.5

// note the f
println(f"height: $height%.5f")
height: 1.50000
height: Double = 1.5

Arrays

Scala arrays are traditional in tha they are static; once you declare one to be a certain length, it can’t be changed. Interestingly, the individual elements of the array can be change:

// declare and array - this uses type inference
val numbers = Array(2,4,6,8,10)

// could also be
// val numbers: Array[Int] = Array(2,4,6,8,10)

// access it by index (starting at 0)
println(numbers(4))

// it also has the foreach method
numbers.foreach { number =>
    println(number)
}

// update by index 
numbers(1) = 2
10
2
4
6
8
10
numbers: Array[Int] = Array(2, 2, 6, 8, 10)

The Array class has the basic methods you might expect:

numbers.sum
numbers.min
numbers.max
res70_0: Int = 28
res70_1: Int = 2
res70_2: Int = 10

Mapping Arrays

Given Scala’s functional heritage, it’s common to see map function used to transform data structures.

// declare an array
val numbers: Array[Int] = Array(3,6,9,12,15)

// map each "x" in the list to "x * 2" 
val doubledNumbers = numbers.map(x => x * 2)
numbers: Array[Int] = Array(3, 6, 9, 12, 15)
doubledNumbers: Array[Int] = Array(6, 12, 18, 24, 30)

You might be wondering if we can add conditionals to this basic idea to get generators or comprehensions. You bet, using yield.

// create a new array
val numbers = Array(5,10,15,20,25,30)

// conditional in parenthesis if 
val over15 = for(element <- numbers if element > 15) yield element
numbers: Array[Int] = Array(5, 10, 15, 20, 25, 30)
over15: Array[Int] = Array(20, 25, 30)

Dynamic Arrays

What about a dynamic array? Scala’s standard library provides a Java-like ArrayBuffer:

// import the data structure 
import scala.collection.mutable.ArrayBuffer  

// declare one, empty 
val dynamic = ArrayBuffer[Int]()

println(dynamic.length)

// note handy "by" option letting us count by "2"
for(i <- 2 to 10 by 2) {
    dynamic += i
}
println(dynamic.length)
0
5
import scala.collection.mutable.ArrayBuffer  
// declare one, empty 
dynamic: ArrayBuffer[Int] = ArrayBuffer(2, 4, 6, 8, 10)

Generally speaking, Scala is very syntactically consistent; the basic methods have the same names as the regular array:


dynamic.sum
dynamic.min
dynamic.max
res74_0: Int = 30
res74_1: Int = 2
res74_2: Int = 10

Logic, Comparisons, and Control Flow

The control flow in Scala is traditional and straightforward, strongly resembling and C-family language. The comparison operators will also seem familiar.

val numbers = Array(1,2,3,4,5,6,7,8,9,10)

numbers.foreach{ number =>
    // check for even/odd with "=="
    if(number % 2 == 0){
        println("The number is even")
    }
    // scala uses ! for negative comparisons
    else if(number % 2 != 0){
        println("The number is odd")
    }
    // final condition, not activated here 
    else{
        println("Does not compute!")
    }
}
The number is odd
The number is even
The number is odd
The number is even
The number is odd
The number is even
The number is odd
The number is even
The number is odd
The number is even
numbers: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

Functions

A simple function in Scala looks a bit like lambda expressions in other languages and can be defined like this:

// think of => as "yields"
val addTwoNumbers = (x: Int, y: Int) => x + y 

addTwoNumbers(4,5)
addTwoNumbers: (Int, Int) => Int = ammonite.$sess.cmd76$Helper$$Lambda$2850/0x0000000800905a78@2ea8ff5a
res76_1: Int = 9

Using def is for making a method (in this case of the main object)

// notice there is a ":" now 
def introduceYourself(name: String): Unit = {
    println(s"Hello there, my name is $name") // note s + $ for string interpolation - we'll see this again
}

introduceYourself("Russ")
Hello there, my name is Russ
defined function introduceYourself

Default Arguments

Scala uses a Python-like default arguments to avoid method overloading (we use () because there is an arguments list in this function):

// Simply add ' = "Bonnie"' and you're good to go
def introduceYourself(name: String = "Bonnie"): Unit = {
    println(s"Hello there, my name is $name")
}

introduceYourself() // defaults to Bonnie 
introduceYourself("NotBonnie") // uses input we specify
Hello there, my name is Bonnie
Hello there, my name is NotBonnie
defined function introduceYourself

Maps (Paired Data)

// store keys and values 
var stars = Map("Lee" -> "Pace", "Kerry" -> "Bishe'", "MaKenzie" -> "Davis")
// or
// Map[String, String] = Map("Lee" -> "Pace", "Kerry" -> "Bishe'", "MaKenzie" -> "Davis")

println(stars("Lee"))
Pace

It is easy to add new entries:

// the += syntax carries over
stars += ("Scoot" -> "McNairy")
stars += ("Toby"  -> "Huss")

// using keys yields and array which also has "foreach"
stars.keys.foreach{ actor =>
    println(actor + " " + stars(actor))
}
Scoot McNairy
Kerry Bishe'
MaKenzie Davis
Toby Huss
Lee Pace

There is also a “values” method:

stars.values
res81: Iterable[String] = Iterable("McNairy", "Bishe'", "Davis", "Huss", "Pace")

It’s also simple to reverse a mapped/paired structure using mapping:

// simply yield "v", "k", for every "k", "v"
var reversedStars = for((k, v) <- stars) yield (v, k)

Object Oriented Programming

We’ve mostly seen simple imperative programming and hints of Scala’s functional origin but it also an Object Oriented language.

Case Classes

The most simple version of OO Scala is the case class. While a bit foreign to Java folks, they are quite handy. Case classes are generally small, simple, immutable structures, like points on a graph. Let’s define one:

// define a case class with an x and y value 
case class Point(x:Int, y:Int)
defined class Point

That’s it. It’s disarmingly simple compared to a Java object, but it works. Part of this is because it assumes that you want immutable fields unless otherwise specified (part of the functional meets OO approach). Creating one is straightforward and largely familiar to Java folks:

// make a new Point
val myLocation = new Point(1,2)

// access the members
myLocation.x
myLocation.y

//// can't do this:
// myLocation.x = 5
//// unless it was defined like this, specifying they could vary
// case class Point(var x:Int, var y:Int)
myLocation: Point = Point(1, 2)
res84_1: Int = 1
res84_2: Int = 2

Traditional Classes

We will make a simple Person class that has a private value (available only to the class) to represent its age and a String for a name. We will include methods for it to get older and to display the current age. Classes are public by default.

// define a class
class Person {
    // set a field
    private var age = 0
    var name = ""
    
    // method to increase age
    def getOlder { age += 1 }
    
    // method to say age
    def sayAge { println(age) }
}

// make a new instance 
val rando = new Person

// show age before and after method call 
rando.sayAge
rando.getOlder
rando.sayAge

// give the person a name 
rando.name = "Abakus"
println(rando.name)
0
1
Abakus
defined class Person
rando: Person = ammonite.$sess.cmd85$Helper$Person@6162ffa6

What if we wanted to make mandatory fields? We can include them in the parenthesis in a move that will look familiar to Python coders.

// define a person with a name and an age
class Person(val name: String, var age: Int)

//// this would crash "not enough arguments for constructor":
//> val kanye = new Person(name = "Kanye")
///...because it doesn't have the arguments that we told it were needed.

// make a new instance of the class named kanye
val kanye = new Person(name = "Kanye", age = 35)

// show values 
kanye.name
kanye.age
defined class Person
kanye: Person = ammonite.$sess.cmd86$Helper$Person@360cbb22
res86_2: String = "Kanye"
res86_3: Int = 35

Constructors

Constructors allow the writer to dictate behavior that takes place whenever an instance of the class is created (for the uninitiated, the footnotes of this page contain a brief explanation). It’s common, for instance, for an object that reads a file to do so upon to construction. This saves the time of creating the object and then calling a method to have it read the file. In C++ and Java, the constructor is a method of the class that has the same name as the class. In Scala however, it just executes the code immediately inside the class definition. Let’s take a look at a simple example:

class TinyHuman {
    // this is constructor behavior
    println("I have been born and am alive!")
}

// this will print it's greeting even thought we didn't call anything
val newborn = new TinyHuman
I have been born and am alive!
defined class TinyHuman
newborn: TinyHuman = ammonite.$sess.cmd87$Helper$TinyHuman@7e1bdf48

Getters and Setters

Getters and Setters are built into classes by Scala (for the unfamiliar, the footnotes of this page contain a brief explanation). While this might seem wild, the programmer can control them using “var”, “val”, and the “private” keyword to restrict how they are used, allowing full control of the class. The auto-generator methods are “foo” and “foo_” in the Java Virtual Machine code made by compiling Scala.

class Year {
    var month = 1 // starts in Jan 
}

val thisYear = new Year()
thisYear.month            // this will call the internal "foo", in this case, "month"
thisYear.month = 2        // this calls the "foo_", in this case "month_"
defined class Year
thisYear: Year = ammonite.$sess.cmd88$Helper$Year@182a8837
res88_2: Int = 1

Scala will also allow you to define “foo” and “foo_” yourself if you want to (or just foo).

To make Scala write only a getter method declare that value with “val”. Because vals cannot change, it will not bother with setter method.

To make Scala create a getter and a setter, declare an attribute with “var” - an attribute that can change will require a getter and a setter.

Private Attributes

Private attributes work in a Java-like way. Here, we use private to make an attribute that can be incremented by the user but not set to whatever they want as they can’t access it directly:

class Year {
    private var month = 1
    def incrementMonth { month += 1 }
    def showCurrentMonth = println(month)
}

val now = new Year

now.incrementMonth
now.showCurrentMonth
2
defined class Year
now: Year = ammonite.$sess.cmd89$Helper$Year@33d58403

Constructors

Scala generates a standard constructor for all the classes you define.

We can do so using what Scala calls a “Primary Constructor”. This is like a constructor in other languages except that is is implicitly created as part of the class definition.

class Child {
    println("I am alive!")
    println("I have a constructor and it is the best!")
}

// the message will just occur
val kiddie = new Child
I am alive!
I have a constructor and it is the best!
defined class Child
kiddie: Child = ammonite.$sess.cmd90$Helper$Child@965084a

Inheritance

Scala provides a predictable means of single inheritance (Like Java, Scala does not implement multiple inheritance).

// class and method definition in a single line?
class Kid { def talk(): Unit = { println("I say the damnest things") }}

class PreTeen extends Kid{}

// will automatically have the method from Kid even though it is a preteen
val newKid = new PreTeen

newKid.talk
I say the damnest things
defined class Kid
defined class PreTeen
newKid: PreTeen = ammonite.$sess.cmd91$Helper$PreTeen@a4d13c1

Java coders: note that Scala constructors do not require the use of super(), though the languages does support it for access superclass methods in general and it is used the same way as in Java.

Composition

Scala offers “mixins” for composing classes based on functionality.

// define a lover that loves
trait lover {
  def love(): Unit = {
    println("I am a lover!")
  }
}

// define a fighter that fights 
trait fighter {
  def fight(): Unit = {
    println("I am a fighter!")
  }
}

// mix them together to make a rouge 
class rouge(name: String) extends lover with fighter {
  // the rouge can call both of methods from the mixins
  def enGarde(): Unit = {
    love
    fight
    println("I am " + name + "!")
  }
}

val zoro = new rouge("Zoro")            // make a new rouge
zoro.enGarde                            // put foes on notice!
I am a lover!
I am a fighter!
I am Zoro!
defined trait lover
defined trait fighter
defined class rouge
zoro: rouge = ammonite.$sess.cmd92$Helper$rouge@22a12e9e

Overriding a method

Scala supports the “override” keyword to specify a new method behavior. Let’s make a subspecies of Rouge with his own enGarde() protocol:

class revengeSeeker(name: String, warning: String) extends rouge(name) {
  // override the definition of enGarge
  override def enGarde(): Unit = {                                        
    love 
    fight
    println("I am " + name + " " + warning)
  }
}

val inigo = new revengeSeeker(name = "Inigo Montoya", warning = "Prepare to die!")
inigo.enGarde
I am a lover!
I am a fighter!
I am Inigo Montoya Prepare to die!
defined class revengeSeeker
inigo: revengeSeeker = ammonite.$sess.cmd93$Helper$revengeSeeker@4b5258dc

Footnotes

What’s a Constructor?

For the unfamiliar, a constructor is a special method that activates when a class is created. They keep the user from having to specify behavior for each object created after it is initialized.

What are Getters and Setters?

Getters and Setters are worth a discussion in their own right, but for a working knowledge, they are methods to access or change object attributes. They are used when there is a reason to conceal the traits from the end-user. A good example of when to use a Getter would be in a class where a Person class with and “age” attribute that should not be able to get younger (as provided in “Scala for the Impatient”). It’s easy for the programmer of the class to write code to keep the age from running if it doesn’t fit the criteria designated by the Setter.