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