About this book

This book teaches you how to build and contribute to Scala programs, recognizing common patterns and techniques used with the language. You’ll learn how to write concise, functional code with Scala. After an introduction to core concepts, syntax, and writing example applications with scalac, you’ll learn about the Scala Collections API and how the language handles type safety via static types out-of-the-box. You’ll then learn about advanced functional programming patterns, and how you can write your own Domain Specific Languages (DSLs). By the end of the book, you’ll be equipped with the skills you need to successfully build smart, efficient applications in Scala that can be compiled to the JVM.

Publication date:
July 2018
Publisher
Packt
Pages
186
ISBN
9781789533835

 

Chapter 1. Setting up the Development Environment

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.

 

Simple Program


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
   }
}

Definitions: Packages, Imports, and Objects

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.

Object Definition

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.

The main Method

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() = { … } }

Inside main

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
       }
}

}
 

Structure of a Scala Project


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.

Basic sbt Commands

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.

Now let's see our sample project and sbt tool.

Activity: Performing Basic Operations with sbt: Build, Run, Package

  1. Install sbt on your computer, if not installed beforehand.

  2. Start the sbt console by typing sbt console in the root directory of the 1-project (where build.sbt is situated).

  3. Compile the code by typing the compile command into the sbt console.

  4. Run the program by typing the sbt run command into the sbt console.

  5. When running this, say bye to the bot and return to the console.

  6. Package the program by typing package into the sbt console.

IDE

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.

Activity: Loading and Running a Sample Project in the IDE

  1. Import our project:

    • Go to File -> Import -> navigate to build.sbt

  2. Open the program in IDE:

    • Start IDEA

    • Press Open

    • Select day1-lesson1/1-project/build.sbt

  3. In the dialog window, which asks whether to open it as a file or as a project, select project.

  4. On the left part of the project's structure, unfold src entry.

  5. Click on main.

  6. Ensure that you can see main, as specified in the code.

  7. 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:

  1. Select Run/ Edit Configuration.

  2. Select Application.

  3. Set the application's name. In our case, use Chatbot1.

  4. Set the name of the Main class. In our case, it must be com.packt.courseware.Chatbot1.

  5. Actually run the application: select Run, then Chatbot1 from the dropdown menu.

REPL

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:

  1. Open the sbt tool.

  2. Open REPL by typing the following command:

    sbt console
  3. 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.

Obtaining the Time Request from Our Chatbot Program

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

  1. Check for time to match the statement:

    case "time" =>
  2. Retrieve the current time using the Java API. Use the now method of java.time.LocalTime:

         java.time.LocalTime.now()
  3. 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.

 

Base Syntax


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/.

Base Syntax for Definitions

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:

  1. Open REPL by typing the following command in sbt:

    sbt console
  2. Type in the following commands in REPL:

    >  object ZeroPoint {
    >     val x:Int = 0
    >     val y:Int = 0
    > }

Base Syntax for Expressions

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.

    Note

    Any method with an argument can be used as a binary operator. A set of predefined binary operators are similar to Java:

  • unary: !x

  • Constructors: new x creates an instance of class x.

  • Assignments to mutable variables:

    • y = 3: Assigns a value of 3 to y.

    • 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 if A and B 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.

  1. You should have already opened project1. If you haven't, import it into the IDE.

  2. Insert the new method inside the object definition.

  3. 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
     }
}
 

Unit Testing


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.

Adding a Test to Our Project

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.

  1. In the command-line environment, navigate to the root of the project and select the following test:

      Lesson 1/2-project
  2. If you are using a Unix/Linux machine and your code is situated in courses/pactscala of your home directory, then run the following command:

     > cd  ~/courses/packscala/Lesson 1/2-project
  3. Run the following command :

        > sbt test
  4. 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.

  1. Open the project in the IDE.

  2. Navigate to Run/ Edit Configurations:

  3. Choose s bt test as the configuration.

    • Check the checkbox Use sbt:

  4. Select Run sbt-test.

Inside Tests

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.

  1. Add one more test to the same file: src/test/scala/com/packt/courseware/l1/ExampleSpec.scala in 2-project

  2. We write one trivial test, which asserts the false expression:

          test("trivial")  {
                assert(false)
           }
  3. Run the test and look at error reporting.

  4. Invert the expression in assert so that the test passes:

          test("trivial")  {
                assert(true)
           }
  5. Run the sbt test again to ensure that all of the tests pass.

Running Tests for Chatbot

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.

Note

Please import Lesson 1/2-project into your IDE.

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.

  1. Add a second test to the StepTestSpec class in our project:

    test("after bye, timeToBye should be set to true")
    {
    
    }
  2. 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 to true:

      assert(! r.timeToBye)
  3. The whole code should be as follows:

    test("after bye, timeToBye should be set to true") {  
    val r = Chatbot2.step("bye")
    assert(! r.timeToBye)
    
  4. 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.

  1. Add the following code to the match statement so that it checks for the date command, which should output the local date in DD:MM:YYYY format:

      case "date" => LineProcessResult(LocalDate.now().format(DateTimeFormatter.ofPattern("dd:YYYY-MM")),false)
  2. Add a test case for this function.

  3. 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
    }
 

Summary


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.

About the Authors

  • Mads Hartmann

    Mads Hartmann is a software engineer with a fondness for automation and programming languages, especially statically typed functional ones. He holds a master’s degree in computer science from the University of Copenhagen and he is currently working as a full-stack engineer at Family. He is active in the Copenhagen developer scene and has organized a meetup group for people interested in Scala.

    Browse publications by this author
  • Ruslan Shevchenko

    Ruslan Shevchenko is a system architect and a software developer who is focused on building reliable software systems. During his career patch, he was involved in projects using many languages, from Scala, Java to C++, C, Perl, and Tcl in numerous areas, such as telecommunications, OSS/billing systems, finance, code analysis, social integration, system utilities. In terms of architecture, his specialist domains are large-scale software systems and distributed processing.

    Browse publications by this author
Professional Scala
Unlock this book and the full library FREE for 7 days
Start now