Before we start writing the various programs in this book, let's talk a little about the Scala language itself. Why is it necessary, and what has made Scala unique? What are the most important aspects of the language?
Scala was created in 2001 in EPFL (École Polytechnique Fédérale de Lausanne), by Martin Odersky. This is the same lab where Pascal language (widely used up to the end of the 1990s) was created.
Scala is an abbreviation for 'Scalable Language'—a language which can be scaled, that is, it allows you to write complex systems with gigantic amounts of functionality. As specified on Scala's home page: " Scala combines object-oriented and functional programming in one concise, high-level language."
Note
You can visit Scala's official home page here: https://www.scala-lang.org/
By the end of this chapter, you will be able to:
Recognize the structure of a Scala project
Identify the use of Scala's sbt tool (interactive build tool) for building and running your project
Identify how to use the IDE
Implement interactions with a simple chatbot
Scala is built on top of the JVM platform (the Scala program is compiled to use JVM bytecode).
Now, the language is used as one of the most preferred platforms in many areas, such as high-load soft-realtime applications, ad servers for data science toolkits.
Some characteristics of Scala are as follows:
An advanced type system, which makes Scala superior (but at the same time, more complex) compared to most other industrial programming languages.
Static typing, which allows you to write code in a safe way when errors are checked during compilation.
In this chapter, we will learn the basics of Scala, such as what the simple Scala program looks like and what a typical developer flow is. A significant part of development is interaction with tools—build tools, dependency extractors, IDEs, and so on, which form the tool ecosystem with the language. We will build a simple program using mainstream tools.
In this section, we will be covering the structure of a basic Scala program. We will be covering definitions such as packages, imports, and objects. We will also be looking into the main method of a Scala program.
Let's create the simplest possible program in Scala. We will implement a program which will print "Hello World" on the screen. The structure of this program is defined as follows:
package com.packt.courseware import scala.io.StdIn object Chatbot1 { def main(args: Array[String]):Unit = { // do something } }
If you look at the preceding code, the first line is a package name. In our case, this is
com.packt.courseware
.
All compilation units are organized into packages. Packages can be nested, forming hierarchical namespaces for code objects.
When a compilation unit has no package declaration, it belongs to a so-called '
default
' package. Modules from a default package can't be imported from another package.
Usually, the source directory in a Scala project is organized in the same way as packages. This is not mandatory, but becomes a rule of thumb. Some tools (such as IDEs) use these conventions for default project settings.
Now we will look at
import
statements.
Here, we define the object
Chatbot1.
If you are familiar with the traditional classes, since they are implemented in Java, you can look at the object of a class with one default instance, that is, an object is an implementation of the singleton pattern: on the JVM level, the object definition creates a class and one predefined instance of this class.
Finally, the
main
method is an entry point for our program. It must accept an array of strings (command-line arguments) and return a unit.
Historically, the
main
method name is used in Scala. This is because the Java language is following the same tradition, which takes the name of an entry method from C, which take this from BCPL.
The method is defined as follows:
package com.packt.couserware object X { def f() = { … } }
The
main
method is an essential part of any Scala program. The execution of a program first starts from the
main
method.
Let's look inside the
main
method:
def main(args: Array[String]): Unit = { val name = StdIn.readLine("Hi! What is your name?") println(s" $name, tell me something interesting, say 'bye' to end the talk") var timeToBye = false while (!timeToBye)timeToBye = StdIn.readLine(">") match {case "bye" => println("ok, bye") truecase _ => println("interesting...")false} }
Here, we define an immutable value with the name
name
, which keeps the user's input from
stdin
. Scala is a statically typed language, and so the value is of type
String
.
As we can see, the type of the value is not explicitly written, but automatically inferred from its context.
At the next line, the value is printed using the "string interpolation" operator: In a string with a prefix of
s
, all occurrences of expressions inside
${}
brackets in strings are replaced with values of these expressions, casted to strings. For simple identifiers, we can
omit {}
brackets, for example, in a string interpolation of
s"x=$y"
, the value of y will be substituted instead with
$y
.
var timeToBye
is a mutable variable with a
Boolean
type. Unlike values, mutable variables can be assigned more than once.
Looking forward at the loop, we can see that the program is trying to be a good listener and answer
interesting
to any message, except
bye
.
The result of the case statement is assigned to
timeToBye
, and is checked in the
while
loop condition
Scala, as a multiparadigm language, has both mutable and immutable variables. For nearly any task, we can choose more than one way of implementing this.
If guidelines exist, where should we use mutable variables and where should we use immutable variables?
Generally, reasoning about immutable variables is simpler. The usual heuristic is to use immutable values as much as possible, leaving mutable variables for performance-critical sections and state-check language constructs (such as while loops).
In our small example, we can eliminate the mutable flag by putting an expression for the loop exit condition inside
while
. The resulting code is smaller and better to read, but adding new functionality becomes harder. Yet there is one possibility—use the
recursive
function instead of the loop language construction.
Now let's add some functionality to our
chatbot
: when the user asks for the
time
, the
chatbot
should report the current time.
To do this, we must retrieve the current time using the Java API and display the output of the time using string interpolators.
For example, use the
now
method of
java.time.LocalTime.
The code used to display this will be
println("time is ${java.time.LocalTime.now()}").
The following is the code for this functionality, but we will actually implement this after setting up the working environment we will be playing with:
package com.packt.coursewarepackage com.packt.courseware import scala.io.StdIn object Chatbot1 { def main(args: Array[String]): Unit = { val name = StdIn.readLine("Hi! What is your name?") println(s" $name, tell me something interesting, say 'bye' to end the talk") var timeToBye = false while (!timeToBye) timeToBye = StdIn.readLine(">") match { case "bye" => println("ok, bye") true case "time" => println(s"time is ${java.time.LocalTime.now()}") true case _ => println("interesting...") false } } }
Let's look at our
chatbot
program in a complete runnable project. Let's navigate to the
/day1-lesson1/1-project
directory in our code supplement.
Note
The code is available on Github at the following link: https://github.com/TrainingByPackt/Professional-Scala

The preceding diagram is the typical directory structure of a Scala project. If you are familiar with the Java tools ecosystem, then you will notice the similarities between the
maven
project layout.
In
src
, we can
see project sources (
main
and
test
).
target
is a place where output artifacts are created, whereas
project
is used as a place to
internally build the project. We will cover all of these concepts later on.
organization := "com.packt.courseware"name := "chatbot1"version := "0.1-SNAPSHOT" scalaVersion := "2.12.4"
The head of any project is its
build.sbt
file. It consists of the following code:
The text inside it is a plain Scala snippet.
organization
,
name
, and
version
are instances of
sbt.key
. For this point of view,
:=
is a binary operator defined on
keys
. In Scala, any method with two arguments can be used with the syntax of a binary operator.
:=
is a valid method name.
build.sbt
is interpreted by the
sbt
tool.
Note
sbt
– The original intention for the name, when
sbt
was created by Mark Harrah, was '
Simple Build Tool
'. Later on, the author decided to avoid such a decipherment, and kept it as it was. You can read about the details of
sbt
here:
https://www.scala-sbt.org/1.x/docs/index.html.
We will now
talk about the basic
sbt
commands.
sbt
compile should compile
the project and live somewhere in its target compiled Java classes.
sbt run
executes
the
main
function of the project. Therefore, we can try to interact with our
chatbot
:
rssh3:1-project rssh$ sbt run [info] Loading global plugins from /Users/rssh/.sbt/0.13/plugins [info] Set current project to chatbot1 (in build file:/Users/rssh/work/packt/professional-scala/Lesson 1/1-project/) [info] Running com.packt.courseware.Chatbot1 Hi! What is your name? Jon Jon, tell me something interesting, say 'bye' to end the talk
>qqq interesting.. >ddd interesting... >bye ok, bye [success] Total time: 19 s, completed Dec 1, 2017 7:18:42 AM
The output of the code is as follows:
sbt package
prepares
an output artifact. After running it, it will create file called
target/chatbot1_2.12-0.1-SNAPSHOT.jar
.
chatbot1
is the name of our project;
0.1-SNAPSHOT – version. 2.12
is the version of the Scala compiler.
Scala
guarantees binary compatibility only within the scope of a minor version. If, for some reason, the project still uses
scala-2.11
, then it must use the library, which was created for
scala-2.11
. On the other hand, updating to the next compiler version can be a long process for projects with many dependencies. To allow the same library to exist in the repository with different
scalaVersions
, we need to have an appropriate
suffix in the jar file.
sbt publish-local
– publishes the artifact on to your local repository.
Install sbt on your computer, if not installed beforehand.
Start the
sbt
console by typingsbt console
in the root directory of the1-project
(wherebuild.sbt
is situated).Compile the code by typing the
compile
command into thesbt
console.Run the program by typing the
sbt run
command into thesbt
console.When running this, say
bye
to the bot and return to the console.
Another part of the developer toolbox is an IDE tool (Integrated Development Environment). For our book, we will use Intellij IDEA community edition with the Scala plugin. This is not the only option: other alternatives are scala-ide, based on IBM Eclipse and Ensime (http://ensime.github.io/), which brings IDE features to any programmable text editors, from vi to emacs.
All tools support importing the project layout from
build.sbt
.
Go to
File
->Import
-> navigate tobuild.sbt
Open the program in IDE:
Start IDEA
Press
Open
Select
day1-lesson1/1-project/build.sbt
In the dialog window, which asks whether to open it as a file or as a project, select
project
.On the left part of the project's structure, unfold
src
entry.Click on
main.
Ensure that you can see
main
, as specified in the code.Ensure that project can be compiled and run via the
sbt
console.
For running our project from the IDE, we should edit the project's configuration (Menu:
Build
/
Edit configuration
or
Run
/
Edit
configuration, depending on which version of IDEA you are using).
Running the Project from IDE:
Another tool that we will frequently use is REPL (Read Eval Print Loop). It is often used for quickly evaluating Scala expressions.
From
sbt
, we can enter REPL mode with the help of the
sbt console
command. Let's try some
simple expressions.
Now, we'll look at how to evaluate expressions. Follow these steps to do so:
Open the
sbt
tool.Open
REPL
by typing the following command:sbt console
Type the following expressions and press Enter:
2 + 2
"2" + 2
2 + "2"
(1 to 8).sum
java.time.LocalTime.now()
Please note that we can have an interactive Scala
playboard
inside IDE by creating a special file type: a Scala Worksheet. It's useful, but is mainly for demonstration purposes.
For now, let's return to our task: modifying the
chatbot
program so that it replies with
the current time, as requested by the use of
time
. Let's learn how to do this:
Steps for C ompletion
Check for
time
to match the statement:case "time" =>
Retrieve the current time using the Java API. Use the
now
method ofjava.time.LocalTime
:java.time.LocalTime.now()
Display the output of the time using string interpolators, as follows:
println("time is ${java.time.LocalTime.now()}")
The
main
method will look like this:
def main(args: Array[String]): Unit = { val name = StdIn.readLine("Hi! What is your name?") println(s" $name, tell me something interesting, say 'bay' to end the talk") var timeToBye = false while (!timeToBye)timeToBye = StdIn.readLine(">") match {case "bye" => println("ok, bye")truecase "time" => println(s"time is ${java.time.LocalTime.now()}")truecase _ => println("interesting...")false} }
After we prepare and package our artifacts, we need to run them as well.
In this book, we will
use the running system from unpackaged sources via
sbt
(as in the early days of Ruby applications), assuming that sources and
sbt
tools are accessible from the production environment. Using this, we can use build tool commands for sources such as
sbt run
. In real life, packaging for production is a bit more complex.
Popular methods for doing this are as follows:
Preparing a fat jar (which includes all dependencies). An
sbt
plugin for this exists, which can be found at the following link: https://github.com/sbt/sbt-assembly.Preparing a native system package (which includes jars, dependencies, custom layouts, and so on). There is also an
sbt
plugin to create native system packages, which can be found at the following link: https://github.com/sbt/sbt-native-packager.
Now that we can use REPL, let's understand the base Scala syntax. For now, it's not necessary to learn it in detail, but let's get familiar with it by using an example.
Note
For a formal, detailed description, refer to the SLS: Scala Language Specification here: http://scala-lang.org/files/archive/spec/2.12/.
Scala compilation unit – This is a set of definitions inside an entity (template-entity), which can be an object, a class, or a trait. We will speak about the Object-Oriented part of the Scala language in detail later. Now, let's look at the basic syntax. Let's define some classes in REPL:
> class X { def f():Int = 1 } > Class X defined // answer in REPL
Definitions inside the entity can be nested entities, functions, or values:
> def f():Int = 1
Here, the function
f
is defined, returning
1
. We will talk about this function in detail in
Chapter 3,
Functions. Now, let's stay on the top-level view:
> val x = 1
Here, the value
x
is defined with value
1
:
> var y = 2
Here, the mutable variable
y
is defined with value
2
.
Other high-level entities include objects and traits. We can create objects by writing object or trait definitions:
> object O { def f():Int =1 } > trait O { def f():Int =1 }
We will talk about classes, objects, and traits in the next chapter.
Now, let's look at defining an object in REPL with the name ZeroPoint.
Steps for Completion:
Scala is an expression-based language, which means that everything is an expression (in the right-hand side of function and value/variable definitions).
Some of the base expressions are:
Primitive expression: Constant or value/variable name.
Function calls: These can be:
Usual function calls
f(x, y)
.Operator call syntax:
binary:
x + y
.
unary:
!x
Constructors:
new x
creates an instance of class x.Assignments to mutable variables:
y = 3
: Assigns a value of3
toy
.x = 3
: This is a compiler error, and a value can't be assigned.
Block:
{ A; B }
The value of a block expression is the last expression. Note that
;
can be omitted ifA
andB
are situated on different lines. The syntax for this is shown as follows:{ A B }
The preceding syntax will have the same output as
{ A; B }
.
Control structures
if
statement:> if (1 == 1) "A" else "B" - let's eval one in REPL
match/case expressions:
> x match { case "Jon" => doSomethingSpecialForJon() case "Joe" => doSomethingSpecialForJoe() case _ => doForAll() }
Loops:
while
/do
var i=0 var s=0 while(i < 10) { s = s+i i = i +1 }
Do
/while
Foreach
,for
Shortcuts for height-order functions will be described in detail in, Chapter 4, Scala Collections.
We'll look at defining a main function which prints something onscreen and calls the main function.
You should have already opened
project1
. If you haven't, import it into the IDE.Insert the new method inside the object definition.
Insert call at the
main
method.
The full method should look something like this:
object Chatbot1 {def printHello():Unit = { println("Hello")}def main(args: Array[String]): Unit = { printHello() … // unchanged code here } }
In any program which is bigger than arithmetic operations, programmers should make themselves comfortable when it is possible to ensure that new changes are not breaking old functionalities.
The most common technique for this is unit testing, which is where the programmer tests the functionality of the code in parallel with its development by creating a test code which will verify that the code really satisfies their requirements.
The theme of this section will be introducing tools for unit testing in Scala.
Let's add tests
to our small program. We'll import
<for-students/lesson1/2-project>
in our IDE.
This is the directory schema of a Scala project. For adding tests, we should do the following:
Add test dependencies to
build.sbt
Write tests in the source test directory
For adding dependency, let's add the following line to our
build.sbt
:
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.4" % "test"
It's an
expression in Scala DSL (domain-specific language), which means that we should add
scalatest
to our set of library
dependencies. Operators
%%
and
%
are used for forming the name and classifier for published artifacts. You can refer to the
sb
t
documentation for more detail:
http://www.scala-sbt.org/1.x/docs/Library-Dependencies.html.
Before compilation,
sbt
will download
scalatest
from a publicly available repository (Maven central), and when running tests, it will add
scalatest
to the classpath.
We will
now run
sbt
tests from the command line.
In the command-line environment, navigate to the root of the project and select the following test:
Lesson 1/2-project
If you are using a Unix/Linux machine and your code is situated in
courses/pactscala
of your homedirectory
, then run the following command:> cd ~/courses/packscala/Lesson 1/2-project
Run the following command
:
> sbt test
You will get the expected output, which will include the following strings:
[info] ExampleSpec: [info] - example test should pass [info] StepTest: [info] - step of unparded word must be interesting
We will now see how to
run
sbt
tests from IDEA IDE.
We'll now run sbt Tests from IDEA IDE.
Now let's look at a simple test:
package com.packt.courseware.l1 import org.scalatest.FunSuite class ExampleSpec extends FunSuite { test("example test should pass") { assert(1==1) } }
Here, we define a class which is inherited from scalatest FunSuite.
The test expression is called. When the
FunSuite
class is initialized and added to a set of tests, the test with
name example test should pass
and assert an expression as an argument. For now, this looks like magic, but we will show you how to build such DSLs in the next chapter.
Let's run our test with the help of
sbt
:
sbt test
This command will run all tests and evaluate the test expression.
Now, we'll add another test.
Add one more test to the same file:
src/test/scala/com/packt/courseware/l1/ExampleSpec.scala in 2-project
We write one
trivial
test, which asserts thefalse
expression:test("trivial") { assert(false) }
Run the test and look at error reporting.
Invert the expression in assert so that the test passes:
test("trivial") { assert(true) }
Run the
sbt
test again to ensure that all of the tests pass.
Remember that,
when writing
chatbot
, we want to test one functionality. Our original program only has one function (
main
), which contains all of the logic and can't be split into testable parts.
Let's look at Version 2.
package com.packt.courseware.l1 import java.time.LocalTime import java.time.format.DateTimeFormatter import scala.io.StdIn case class LineProcessResult(answer:String,timeToBye:Boolean) object Chatbot2 { def main(args: Array[String]): Unit = { val name = StdIn.readLine("Hi! What is your name? ") println(s" $name, tell me something interesting, say 'bye' to end the talk") var c = LineProcessResult("",false) while(!c.timeToBye){ c = step(StdIn.readLine(">")) println(c.answer) } } def step(input:String): LineProcessResult = { input match { case "bye" => LineProcessResult("ok, bye", true) case "time" => LineProcessResult(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")),false) case _ => LineProcessResult("interesting...", false) } } }
Here, we see some new constructs:
LineProcessingResult
is a case class, where the result of processing one of the lines (that is, the
chatbot
answer and quit flag) is stored.
What is the word
case
before class?
case
classes can
participate in pattern matching (while we call one
case
) and are usually used for data objects. We will look at
case
classes during the next chapter. It is important to see that an instance of
case
classes can be created with the
LineProcessingResult(x,y)
syntax (that is, without
new
) and an argument to case class constructors (
answers
and
timeToBye
), which automatically become instance variables of the
case
class.
The functionality of processing one line is encapsulated in the
step
method, which we can test.
Step
receives input from the method argument, not from
System.in
, therefore making it easier to test. In the case of directly testing the
main
method, we will need to substitute
System.in
before
test
and return one back after the test is finished.
Ok, let's focus on the first test:
package com.packt.courseware.l1 import org.scalatest.FunSuite class StepTestSpec extends FunSuite { test("step of unparded word must be interesting") { val r = Chatbot2.step("qqqq") assert(! r.timeToBye) assert(r.answer == "interesting...") } }
Writing the second test in the same manner will be an easy task. We will look at this in the following exercise.
Now, let's add the second test, which checks bye.
Add a second test to the
StepTestSpec
class in our project:test("after bye, timeToBye should be set to true") { }
In this test:
Call the step function with
bye
as a parameter:val r = Chatbot2.step("bye")
Check that after this call that
timeToQuit
in the returned class is set totrue
:assert(! r.timeToBye)
The whole code should be as follows:
test("after bye, timeToBye should be set to true") { val r = Chatbot2.step("bye")
assert(! r.timeToBye)Run
sbt test.
A more complex task would be to write a test for the time query.
Please note that we can't run the test with the concrete time value, but at least we can be sure that the bot answer can't be parsed back to the time form.
So, what can we do to check the line answer and try to transform it back to time? The solution is provided in the following code:
test("local time must be parser") { val r = Chatbot2.step("time") val formatter = DateTimeFormatter.ofPattern("HH:mm:ss") val t = LocalTime.parse(r.answer,formatter)// assertion is not necessary }
Note that assertion is not necessary. If time does not satisfy the given format, then an exception will be thrown.
It is a good practice to separate functional and effects time for testing. To do this, we will need to substitute the provider of the system time via own.
This will be the first practical task in the next chapter.
Now, let's add the date command to our chatbot program.
Add the following code to the match statement so that it checks for the
date
command, which should output the local date inDD:MM:YYYY
format:case "date" => LineProcessResult(LocalDate.now().format(DateTimeFormatter.ofPattern("dd:YYYY-MM")),false)
The resulting code will be as follows:
test("local date must be parser") { val r = Chatbot2.step("date") val formatter = DateTimeFormatter.ofPattern("dd:MM-YYYY") val t = LocalDate.parse(r.answer,formatter)// assertion is not necessary }
We have reached the end of the chapter. In this chapter, we learned various aspects of setting up the development environment. We covered the structure of a Scala project, and we identified the use of
sbt
for building and running projects. We covered REPL, which is a command-line interface for running Scala code. We also covered how to develop and run code over the IDEA IDE. Finally, we implemented interactions with our simple
chatbot
application.
In the next chapter, we will cover the structure of a Scala program and dive deep into the object-oriented properties in Scala, such as like classes, objects, and traits. We will also cover the syntax for calling functions and various parameter-passing models.