Keywords

These keywords were added by machine and not by the authors. This process is experimental and the keywords may be updated as the learning algorithm improves.

Scala has grown in popularity in the last years. Some describe the Scala language as the new “golden boy” of programming languages. More large companies have begun to adopt Scala for their core business needs, thus improving the popularity of the language and, of course, the market for it.

The popularity of the language is connected to the nature of the language itself. Scala borrows more of its syntax from other popular languages. For example, the method is declared like C but with optional braces.

At first glance, Scala looks like a dynamic language, such as Ruby or Python, but it is a strong static-type language, with all the advantages of this type.

Adding to all this, Scala has such features as for statement expressions, infix/suffix, and local type inference notation.

The nature of the language is perfect for domain specific languages (DSLs) . Scala combines functional programming with object-oriented programming. Therefore, with Scala, when we must create a DSL , we can rely on a functional language to help us to develop an immutable function. On the one hand, this helps to ensure consistent results. On the other, most of the patterns used to create a DSL employ an object-oriented paradigm, which means that with Scala, we can also have the paradigm for creating the DSL .

In this chapter, I provide a brief introduction to the Scala language and highlight the main features of the language. The rest of the book is devoted to improving the reader’s knowledge of the language, to create some DSL projects.

I suggest using the REPL (Read-Evaluate-Print Loop) for use in the sample code for this chapter, because it provides immediate feedback about the operation we want to execute.

FormalPara Note

Since Scala 2.11, the syntax to exit from the REPL has changed. If you have used the command exit() previously, you will realize that this command is no longer valid. Now, to exit, users must employ the sys.exit() command.

Basic Syntax

Scala is basically a strongly typed language, this means that we can annotate types for the following:

  • Variable and value

  • Method and function argument

  • Method and function return type

For many programmers, this is nothing new. Languages such as Java or C# use the same kind of syntax. The best way of seeing how to use the syntax is to “get your hands dirty.” Therefore, open the REPL and try some basic Scala commands.

Note

Scala runs on a JVM, but a big difference with Java is how Scala de-allocates unused memory. Scala automatically frees memory when data is no longer used.

To open the REPL , go to the command line and insert the command Scala. This will open the Scala interpreter, as follows:

$ scala Welcome to Scala 2.12.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_131). Type in expressions for evaluation. Or try :help. scala>

At first glance, the REPL looks like the interpreter of the interpreted language, such as Ruby or Python, but there is a big difference. Scala is a compiled language, which means that the REPL compiles the code and executes first to present the result.

Start writing some code to see how Scala works, such as

scala> 2+2 res0: Int = 4

Now, we can see Scala execute the code and create a temporary variable to assign the result. However, because Scala is typed, it defines the type of variable, in this case Int.

In Scala, the operators +, -, etc., are a simple function. In this case, writing 2 + 2 is equal to having a method with the left operand. The REPL is very useful in learning Scala, because it provides immediate feedback regarding the operation.

Variable and Value in Scala

With Scala, we can define two kinds of variables:

  • A mutable variable , which is created with the reserved word var

  • An immutable value , created with the reserved word val

This is probably the biggest difference from other languages. In Scala, it is high advisable to use the immutable variable val, because this doesn’t break the rule of functional programming. I will discuss this rule later in the chapter.

The syntax for creating a variable or a value is the same: <kind> <name> : <type> = <value> . Now try the variable with the REPL and note the difference between a mutable and immutable variable. The first type of variable we declare is the mutable variable , declared with var.

scala> var num:Int = 4 num: Int = 4 scala> num = 8 num: Int = 8

Here, as you can see, we create a variable and assign the value of the variable. In this case, we define the type of the variable. We can change the value simply by calling the variable and assigning the new value. There is no difference in how this is done in other languages.

scala> num * 2 res0: Int = 8 scala> res0 + 2 res1: Int = 10

The statement that follows is perfectly valid. In the event that we have not assigned the name of the variable, Scala creates a temporary variable and associates the result with this variable. In this way, we can easily use the temporary variable to execute some other operations. Try to see now how an immutable variable works.

scala> val new_num = 4 new_num: Int = 4 scala> new_num = 8 <console>:12: error: reassignment to val        new_num = 8

In this case, we created a variable new_num, but we haven’t explicitly specified a type. Scala inspects and assigns the correct type. The process for creating the val is exactly the same as for creating a var. The only difference is that if we try to reassign the value, we obtain an error. For many developers, it can be strange to use an immutable variable instead of a mutable variable , but if you look at your code, you can see how simple it is to replace the mutable variable with an immutable one.

Naming in Scala

Scala allows you to name a variable with any letter, number, or some special operator characters. According to the following from the Scala Language Specification, we learn how to define these operator characters:

…all other characters in \u0020-007F and Unicode categories Sm [Symbol/Math]…except parentheses ([]) and periods.

Following are some rules for combining letters, numbers, and characters when naming identifiers in Scala:

  • A letter followed by zero or more letters or digits, for example, var a, var AabcdA, var a1b

  • A letter followed by zero or more digits, underscores (_), or letters, for example, var a_b or val a_ = 10

  • An underscore (_) followed by zero or more letters or digits, for example, var _abcd_

First Example in Scala

Now try to write a simple bubble sort algorithm in Scala.

def bubbleSort(arr_input: Array[Int]): Array[Int] = {   val size = arr_input.size - 1   for (a <- 1 to size) {     for (b <- size to a by -1) {       if (arr_input(b) < arr_input(b - 1)) {         val x = arr_input(b)         arr_input(b) = arr_input(b - 1)         arr_input(b - 1) = x       }     }   }   arr_input }

This simple example shows some Scala functionality. First, we see how to use an immutable variable instead of a mutable one. Starting with this simple example, we can define the principal Scala syntax.

Define a Method and Function in Scala

The syntax for defining a function in Scala is similar to that of any other language. The structure is the following:

def  function_name ([list of parameter]) : [return type]

In the previous example, we defined the method bubblesort:

def bubbleSort (arr_input: Array[Int]): Array[Int]

The list of the parameter can be any valid object of Scala or another function. This characteristic of Scala is called a higher-order function .

The higher-order function is a feature of a functional language such as Scala. For example, imagine that we want to define the function apply and use another function as a parameter.

def apply(internal: Int => String, value:Int) = internal(value)

The function apply takes a function internal as a parameter and applies the function internal to the other parameter, value.

The higher-order function highlights an interesting difference in how Scala defines a function. A function in Scala is an expression that takes a parameter and returns a value.

val addOne = (num:Int) => num +1

Of course, we can have a function without a parameter.

val fixValue = () => 9 val theAnswer=() => 42

The principal difference between functions and methods in Scala is that, this because a method requires a name, the anonymous function is used normally with the functional programming. An anonymous function is not a new concept to Java developers. In Java, when defining the interface, we usually define the event in the anonymous class.

Scala uses the anonymous class in a different way. In Scala, it is possible to define what is known as a first-class function . This function accepts another function for parameters. An anonymous function can be used, for example, to filter a list. The code for this would look like the following:

scala> val list = List.range(1, 20) list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19) scala> val evens = list.filter((num : Int) => num % 2 == 0) evens: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18)

In the preceding code, we create an anonymous function to create the value of the variable evens: list.filter((num : Int) => num % 2 == 0). Here you can see that we used an anonymous function for the parameter of another function.

Classes in Scala

In Scala, a class is defined with this syntax:

class nameOfTheClass([list of parameters]){ body of the class }

The class is the core of object-oriented programming. For experimenting with classes, it is best to open the REPL and try to create a simple Scala class.

scala> class TheQuestion() defined class TheQuestion

The following code shows the basic class in Scala . From what you can see, it is not mandatory for a class to have a body. Of course, a body is not really useful for a class such as that in the sample code, but the simple class used helps us to understand some functionality of the class. For creating an instance of a class, we must use the word new.

scala> val question = new TheQuestion() question: TheQuestion = TheQuestion@1726750

Now it is possible to see that a class has been created for the name and a hexadecimal number. This number is the JVM value associated with the class. A class such as that is not very useful, but it does have all the properties of a simple class. In the REPL, start to call the name of the variable and then press tab. In this case, Scala shows all the commands that can be used for the class.

scala> question. !=   ->             ensuring   formatted   isInstanceOf   notifyAll      wait ##         ==          eq             getClass       ne             synchronized   ? +    asInstanceOf   equals     hashCode    notify         toString

This code creates a class instance and associates it with a variable. Try now to create a simple class in Scala.

class TheQuestion(){   def theAnswer():Int = {     return 42   } }

The preceding code shows how to create a simple class in Scala . Inside the body of the class, we can define the method exposed by the class. This method defines the operation executed by the class.

To create an instance of the class that uses this, we can employ the following syntax:

scala> val question= new TheQuestion() question: TheQuestion = TheQuestion@e5d3e1

To use the method, we can simply use the dot notation, as in other languages.

scala> question.theAnswer res1: Int = 42

Singleton Object

Scala differs from other languages in how it creates a singleton object . For creating a singleton object, the syntax is similar to what we use for creating a class, but we substitute the word class with object.

object TheQuestion {   def main(args: Array[String]): Unit ={     val theAnswer:Int = 42     println(theAnswer)   } }

You can see that the definition is similar to a simple class. In this case, we have created a main method for use in the object. Because this is a singleton , we don’t require the word new in order to create it. The syntax for creating the instance is like the following:

scala> val answer = TheQuestion.main(null) 42 answer: Unit = ()

The singleton object follows the same rules as other languages. In this case, however, because the method main has an array as a parameter, we use the word null to create a null object.

Types in Scala

In Scala, as in any other language, we can find two kinds of types: numerical, such as Int or Double, and non-numerical types, such as char and string.

The difference between Scala and other languages with regard to types is principally one: in Scala, there is no primitive type. This means that any type in Scala is an object. For example, when we define an Int, we create an instance of an object Integer.

Converting Numeric Types

Scala can automatically convert numeric types from one to another. This can occur only in one direction: from a shorter type to a longer type. Table 1-1 shows the numeric type ranked from the lowest to the highest. Numeric types make it possible, for example, to convert a byte into any other type listed. Note, however, that a Double cannot be converted into any other type.

Table 1-1 Numerical Data Type in Scala

String in Scala

A string in Scala is based on the same kind of string in the JVM. Scala adds some unique features, such as multiline and interpolation.

For creating a String in Scala, we can use double quotes. Inside the double quotes we can write our string.

scala> val theGuide = "don't panic" theGuide: String = don't panic

From the previous example, you can see that a string is very easy to create. You can create a string with special characters using the backslash (\).

scala> val theQuestion= "the Answer to the Ultimate Question of life, \nthe Universe,\nand Everything" theQuestion: String = the Answer to the Ultimate Question of life, the Universe, and Everything

In this case, Scala creates the string with a new line character. This creates the string in multiple lines. It is possible to concatenate the string with the plus sign (+), as follows:

scala> val sayHello = "Hello"+" reader" sayHello: String = Hello reader

In this case, we can see Scala concatenate the string into one single string. It is possible to compare the equality of a string by using the operator ==. Scala differs from Java in that in Scala, we don’t check the equality of the object but the equality of the string values, as follows:

scala> val string_compare_1 = "String 1" string_compare_1: String = String 1 scala> val string_compare_2 = "String 1" string_compare_2: String = String 1 scala> val compare = string_compare_1==string_compare_2 compare: Boolean = true

We can see that the two strings have the same value, which, in Scala, are the same. If we try to compare the strings, the value true is returned.

Multiline String

To create a multiline string in Scala, we use three double quotes after the start of a string.

scala> val theFinalAnswer = """ Six by nine. Forty-two.      | That's it. That's all there is.      | I always thought something was fundamentally wrong with the universe """ theFinalAnswer: String = " Six by nine. Forty-two. That's it. That's all there is. I always thought something was fundamentally wrong with the universe"

Multiline strings follow the same rules as other strings. This means that we can use special characters and comparisons as in a normal string.

A multistring is very useful when we want to add specifically formatted string in a code. For example, if we want to have a JSON string in the code, to prepare a return for an output or simply for a test, we can write the string as follows:

scala> val jsonString: String =      |     """      |       |{      |       |"name":"PracticalScalaDSL",      |       |"author":"Pierluigi Riti",      |       |"publisher":"Apress"      |       |}      |       """ jsonString: String = " { "name":"PracticalScalaDSL", "author":"Pierluigi Riti", "publisher":"Apress" }       "

String Interpolation

In Scala, it is easy to concatenate a string by using the plus sign (+), but there is a niftier way of doing this: string interpolation. With this interpolation, Scala replaces the variable with the string value. To use a variable to interpolate a string, the dollar sign ($) is used.

scala> val hello = "world" hello: String = world scala> println(s"Hello $hello") Hello world

We can see from the preceding sample code that we can create a variable and then substitute it when we print out the string. This technique allows us to maintain clear and compact code that is easy to read and, of course, maintain. We can interpolate a string when assigning another variable too. In this case, we must use the syntax ${<variable name>}.

scala> val sayHello= s"Hello ${hello}" sayHello: String = Hello world

To use the interpolation, we must use the char s, which tells Scala to create a string with the variable we write, and Scala then interpolates the string with the variable.

Note

From a memory perspective, it is better to interpolate a string, because a string, as a JVM/Java object, is immutable. This means that when we use the plus sign (+) to create a string, we create three string objects when we concatenate only two strings. This is because, first, Scala allocates memory to the first string, then the second string, and, finally, the third string, as a concatenation of the previous strings. When we interpolate, we have only two strings, because the second is created based on the substitution of the variable.

Expressions in Scala

Scala is a functional language and, as such, functional programming was the primary intent of the inventor of the language. Given this context, I want to describe what an expression means in Scala.

An expression in Scala is a single line of code that returns a value. This is very important for reducing side effects, because they always have the same response to an operation. The scope of functional programming is to define the function in a mathematical way. This means that every function must always return the same value, if it is always sent the same parameter.

This occurs because the function is essentially immutable and isn’t influenced by changes occurring outside the function. This is done to reduce or further eliminate side effects. Side effects are essentially the result of a change to a variable or an expression that changes a value. When the variable outside changes, this violates the functional programming itself.

We can define different types of expressions in Scala:

  • A simple string, int, or any other

  • A variable

  • A value

  • A function

An expression is very useful for moving from object-oriented programming to functional programming. Expressions are used in everyday programming, but you may not have been aware of this. For example, the syntax

var variable:String = "value"

defines an expression. Using a variable, of course, we can use the same syntax to define a value, as follows:

val variable:String = "value"

In the preceding, an expression has been created with a function, but suppose, for example, you want to define a function for calculating the area of a square.

val square=(x: Int) => x*x

The preceding code indicates how to use a function to create an expression.

Conditional Expression

The conditional expression if..else is the core construction of all programming languages. Scala uses the same logical base of other languages for the if..else conditional expression.

The syntax of the if..else is

if(<Boolean>) <expression>

If the Boolean condition is True, expression executes.

scala> if (10 % 3 > 0) println("Not a multiple") Not a multiple

In this example, we use an expression for checking the Boolean value. If 10 is not divisible by 3 it prints "Not a Multiple", so we can see the use of an if..else in Scala is the same of other languages.

In case we want to define an else condition , we can use this syntax:

if(boolean) expression  else expression

We can now write a more complex if..else condition:

scala> if (10 % 2 > 0) println("Not a multiple") else ("Multiple") res2: Any = Multiple

Pattern Matching Expression

Scala doesn’t have a switch command like Java or C#. In Scala, we have the command match, which is more flexible than switch.

The syntax for the pattern matching is:

<expression> match{         Case <pattern match> => <expression> }

The pattern match can be a value or a regular expression; for example, a simple pattern matching can be

scala> val number1 = 10 number1: Int = 10 scala> val number2 = 20 number2: Int = 20 scala> val max = number1 > number2 match{      | case true => number1      | case false => number2      | } max: Int = 20

Here we can see that we have created two values and that the expression is essentially a simple check of these two values. When we identify the bigger, we write out the number.

Multiple Conditions

You can use more conditions in pattern matching. For example, it is possible to check the month of the year to correspond with the season.

val month = "JAN" val season = month match{   case "DEC" | "JAN" | "FEB" =>     "Winter"   case "MAR" | "APR" | "MAY" =>     "Spring"   case "JUN" | "JUL" | "AUG" =>     "Summer"   case "SEP" | "OCT" | "NOV" =>     "Autumn" }

In this case, we match a string using an “or” and can see that the pattern matching is similar but more powerful than with the switch structure. My suggestion is to play with this pattern to learn best what you can do with pattern matching. We can, of course, use a wildcard to parse the case not actually present.

val month = "JAN" val season = month match{   case "DEC" | "JAN" | "FEB" =>     "Winter"   case "MAR" | "APR" | "MAY" =>     "Spring"   case "JUN" | "JUL" | "AUG" =>     "Summer"   case "SEP" | "OCT" | "NOV" =>     "Autumn"   case _ =>     "Not a month" }

In this case, the code shows the result "Not a month". Of course, it is possible to specify the type of variable we want to use for the pattern matching. Here, we need to define the kind of variable following the case. An example can be if we want to check a value, based on a specific type.

Val theAnswer:Int = 42 val anyAnswer:Any = theAnswer anyAnswer match {   case theAnswer:String => "String Value"   case theAnswer:Int => "Integer Value"   case theAnswer:Double => "Double Value" }

With this simple example, we create a variable, and, after, we assign this variable to a type Any. This kind of variable is the highest in numeric value, and this means that it is possibly associated with any other kind of variable. In the example, we try to check with the pattern matching to identify which kind of value is associated with the variable of the kind Any.

Pattern Guard

A pattern guard is an if expression to check a Boolean condition used for executing the pattern matching. This is useful, for example, when we want to check if a string or object is not null.

val empyString:String = null val empStr = empyString match{   case sea if sea!= null =>     println(s"Received '$sea'")   case sea =>     println(s"Received a null value") }

Range and Loop

A for loop in Scala executes a block of code for a certain number of executions. For example, we can use a loop when we want to iterate all elements of an array.

val myArray:Array[String] = new Array[String](10) for (i <- 0 until myArray.length){   print(s"element of the array $myArray(i)") }

In this example, we create an array of an empty element string. The code initializes all elements to the default value, in the case of string, null. We then use the length of the array to identify the number of the iteration. In Scala, it is possible to use the object Range to create a maximum number of the element.

To create a Range object in Scala, we use the following syntax:

<start integer> to or until <end integer> <increment>

The increment is optional, but if it is not, specify it as 1. Imagine now that we want to create a for loop to show some numbers, as follows:

scala> for (number <- 1 to 12) { println(s"Month $number") } Month 1 Month 2 Month 3 Month 4 Month 5 Month 6 Month 7 Month 8 Month 9 Month 10 Month 11 Month 12

In this case, we count from 1 to 12 and show out a string with the string month and number. We can specify different increments using the word by.

scala> for (number <- 1 to 12 by 2) { println(s"Month $number") } Month 1 Month 3 Month 5 Month 7 Month 9 Month 11

In this case, we see the number is incremented by 2, and this reduces the number of elements generated by the range object. In Scala, it is possible to create a range from a List or Array easily. By using the method toList or toArray, Scala converts the object range directly to a List or an Array. It is preferable to use a List in Scala instead of an array, because a List is an immutable structure. This means that when we create a List, we can’t modify it. The List does not allow side effects, and it is important in functional programming to avoid these.

scala> val day_of_week = (1 to 7).toArray day_of_week: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7) scala> val day_of_week = (1 to 7).toList day_of_week: List[Int] = List(1, 2, 3, 4, 5, 6, 7)

Note

It is possible to omit the parentheses, but in that case, you must use postfixOps. The faster way of doing this is to import the class postfixOps, as follows:

scala> import scala.language.postfixOps import scala.language.postfixOps scala> val day_of_week = 1 to 7 toList day_of_week: List[Int] = List(1, 2, 3, 4, 5, 6, 7)

It is possible to use the word yield to create an IndexSeq object . This object translated the value of the result in a Vector, as follows:

scala> val day_of_week = for (x <- 1 to 7) yield {s"$x"} day_of_week: scala.collection.immutable.IndexedSeq[String] = Vector(1, 2, 3, 4,5, 6, 7)

It is possible to use an iterator guard to execute the increment only in certain conditions. An iterator guard is an if condition for verifying whether to execute the increment first.

scala> val even = for(i <- 1 to 20 if i%2 == 0) yield i odds: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)

Other Loops

In Scala, it is possible to create a loop not only by using the for syntax but by using the while and do..while loops . These loops repeat a statement until a Boolean is false.

var count = 10 while(count > 0){   println(count)   count -=1 } 10 9 8 7 6 5 4 3 2 1

The while syntax is very simple: the condition of execution is checked after the loop. For example, when the value of the variable count is 0, the code is executed. Only when the variable is -1, does the loop stop.

The do..while loop is similar to the while loop. The difference is that the variable is checked before the execution of the loop.

scala> var count = 10 count: Int = 10 scala> do{      |   println(count)      |   count -=1      | }while(count >0 ) 10 9 8 7 6 5 4 3 2 1

We can see that the result is exactly the same. The only difference is that the conditional expression is checked first, to call the new loop. This saves a computational execution and occurs because the do..while loop checks the value after the statement. In this case, when the variable reaches 0, the process is stopped.

Data Structures

Until now, I have presented only the basic syntax for the language, but a real program must memorize the data in the data structure in order to manipulate it. I will now discuss the different data structures we can use in Scala.

In Scala there are six basic data structures, as follows:

  • Array

  • List

  • Set

  • Tuple

  • Map

In the next sections, I will attempt to identify the principal differences between these data structures.

Array

An array is a mutable collection and preserves the order of the element we insert. The data in the array is all the same type. The data is not sorted in order, which means that if we create an array with the value (2,1,3), the element of the array remains in that order. An array can also contain duplicated values.

scala> val myArray:Array[String] = new Array[String](10) myArray: Array[String] = Array(null, null, null, null, null, null, null, null, null, null)

In the preceding code, an empty array is defined for a string of ten elements. Because we haven’t specified the value, Scala fills the array with the default value of a string, in this case, the value null.

We can access an array for reading/modifying a value on the array, by using the index of the array. Say, for example, that we want to change the value of the first element of the array . The code would look like the following:

scala> myArray(0) = "test" scala> myArray res7: Array[String] = Array(test, null, null, null, null, null, null, null, null, null)

Is possible to create an array by just defining the elements of the array itself.

scala> val myArray_new = Array(1,2,3,4,5,6,5) myArray_new: Array[Int] = Array(1, 2, 3, 4, 5, 6, 5)

List

A list is an immutable collection. A list preserves the order of the element we insert in it and, like an array, stores only data of the same type, although it can have a duplicated value.

scala> val myList = List("a","b","c","b") myList: List[String] = List(a, b, c, b)

A list is an immutable collection, which means that it is not possible to update the value. In fact, it is not possible to create a list with a default value. If we try to update a value on a list, Scala returns an exception.

scala> myList(3) = 10 <console>:13: error: value update is not a member of List[String]        myList(3) = 10

Set

A set is an unordered immutable sequence. A set doesn’t preserve the order of the element, and it is not possible to add a duplicate element to the set. If we add duplicate elements, the duplicates are deleted by the set itself.

scala> val numbers = Set(1,2,3,4,4,5,3,3,2,1) numbers: scala.collection.immutable.Set[Int] = Set(5, 1, 2, 3, 4)

Tuple

A tuple is a simple logical collection of data. We can store data, like, for example, user data, without having to define a class.

scala> val servers=("localhost", 80) servers: (String, Int) = (localhost,80)

It is possible to access to the element of a tuple by using the positional index. Tuple is a 1-based container.

scala> servers._1 res0: String = localhost

Tuple can be used with pattern matching as a condition for case. If we must create a tuple of only two elements, we can use the sugar syntax ->, as follows:

scala> 1 -> 2 res1: (Int, Int) = (1,2)

Following is how, in a tuple , we can add more than two elements:

scala> val users=("Pierluigi","Riti",15,9,1975) users: (String, String, Int, Int, Int) = (Pierluigi,Riti,15,9,1975)

Map

A map is an iterable, immutable collection of key/value pair. To create a map, we use the syntax used for creating the tuple. Every tuple is a key/value pair:

scala> Map("one" -> 1, "two" -> 2) res1: scala.collection.immutable.Map[String,Int] = Map(one -> 1, two -> 2)

It is possible to associate another map to a key.

scala> Map("one" ->Map("one" ->1)) res2: scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,Int]] = Map(one -> Map(one -> 1))

Summary

In this chapter, I introduced the basic syntax of Scala. I explained the basic Scala syntax without delving into it deeply but only to provide an understanding of how to use Scala. In the next chapter, we will dive deeper into these basic concepts, and I will introduce other Scala concepts related to design and implementation of DSLs. As I suggested, the best way to learn Scala and unleash the potential of this language is to get your hands dirty with the REPL.