Scala Tutorial: Getting Started with Scala

banner_scala

By Tim Buchalka for Udemy

Check out some of Tim’s other courses on Java and Android development.  Tim also operates the Learn Programming Academy website.

Interested in more than just a Scala guide? Check out a full Scala course.

TABLE OF CONTENTS: CLICK TO JUMP TO A SPECIFIC SECTION

What Is Scala?
Getting Started
Creating a Hello World Project in IntelliJ Idea
Scala Worksheets in IntelliJ IDEA
Simplicity of Scala
Scala Type System Variables & Values
Scala and the Usage of Semicolons
Statements, Expressions and Operators
Loops
Functional Programming in Scala
Scala Functions, and the Return statement
Mutability of Function Parameters
Scala Classes, Constructors, Getters & Setters
Inheritance in Scala
Scala Traits
Final Scala Demo Program


What is Scala?

Scala is a programming language for general software applications. The design of Scala started in 2001, and the first public release was in 2004.

The name Scala is a combination of the words “Scalable” and “Language,” which was chosen to indicate its design goal of growing with the demands of the user base.

Many of the design decisions of Scala are inspired by perceived shortcomings of the Java language with Scala source code compiling to Java Byte Code, allowing it to run on a Java virtual machine.

One of the biggest attractions of Scala is that it has full support for functional programming and has a very strong static type system.

This allows for very concise code, requiring fewer lines of code to achieve the same functionality than many other languages, including Java.

Scala runs on the JVM

As previously mentioned, Scala gets compiled into Java Byte Code (Java) and is executed by the Java Virtual Machine (JVM). Scala and Java share a common runtime, allowing you to freely mix Java and Scala code if you so desire.

Scala executes Java Code

Since Scala gets compiled into Byte Code, Scala can call Java code from a Scala program. Hence, you can thus use all the classes of the Java SDK in Scala, as well as your customized Java classes, or any Java open source projects. Scala has a compiler, interpreter and runtime.

Scala has both a compiler and an interpreter which can execute Scala code

Scala code is compiled into Byte Code by the Scala compiler, which can then be executed by the scala command. The scala has similarity with the Java command, in that it executes your compiled Scala code.

Scala code can be directly executed by the Scala interpreter, without you needing to compile it. The Scala interpreter may come in handy as a Scala script interpreter. It is somewhat like a shell script interpreter on a Unix platform.

Scala runs on the JVM. Java and Scala classes, whether they reside in different projects or in the same one, can be freely intermixed and even execute each other’s code.

Getting Started

There are a number of ways to use Scala. Perhaps the easiest is with an IDE (Integrated Development Environment).

This tutorial will use the IntelliJ IDE, which is an IDE that supports a number of languages, including Scala, and has a great free edition, plus a great interactive environment that is perfect for developers new to the language and those with more experience.

In addition, IntelliJ IDE has Scala Worksheet feature support. Worksheets are a REPL (Read-Evaluate-Print Loop) feature that gives you the best of both worlds: compiled code and interactive testing.

Effectively, you get an interactive interpreter for a statically typed language.

You get to enjoy a best-of-class editor support with code completion, hyperlinking, auto-format, etc. A Scala worksheet in IntelliJ IDEA is a Scala file with an .sc extension, which you can run and get evaluation results in a special view appeared in the editor.

Visit http://www.jetbrains.com/idea and download and install the basic product. It has versions for Windows, Mac OS X and Linux.

Once installed, there are a few simple steps to follow to set up Scala, as you will see in the next section.

Creating a Hello World Project in IntelliJ Idea

To create a new Scala project, open up IntelliJ idea. Once it’s opened, confirm that the Scala plugin is installed. In the IntelliJ Idea window, click on the Configure>Plugins selection.

image20

On the plugins windows, search for Scala and make sure it is installed and enabled. If it is not, install and enable it, and then press OK after installing the Scala plugin.

image19

Once you are back in the IntelliJ Idea start window, click the Create Project, select Scala in the left-hand pane, select Scala in the right-hand pane, and press Next.

image22

image21

In the next window, you need to type in your project name in the Project name field.

Choose Hello World for your first Project name.

image24

If you don’t have a Scala SDK installed, then press the Create button in the Scala SDK field.

image23

Then click Download and select the latest version of the Scala SDK. At the time this tutorial was created, the current version was 2.11.7, but you should select the most recent version.

After selecting the recent version of Scala, press OK to start downloading.

image26

After it finishes downloading, you should see it appear automatically selected in the Scala SDK field. If not, select it from the drop-down list. Press Finish to finally create your Scala Project.

image25

Congratulations — you have successfully created your Scala Project.

image29

Scala Worksheets in IntelliJ IDEA

Step 1: Create a Scala worksheet as shown below.

image27

Step 2: Give the worksheet a name of your choice.

image28

Step 3: It will start with a blank worksheet.

image30

Step 4: Type in and run your code. Type the code shown below and it will automatically run, with results shown in the right pane. Alternatively, you can click the green button at the top that says, “Evaluate Worksheet”.

image31

Demonstration

As another example, paste the code below in the left pane of your Scala worksheet as shown in the image, and run the code.

image32

Simplicity of Scala

Scala, as you will see in this tutorial, does a lot of the grunt work and plumbing for developers. Let’s look at an example comparing Java code to Scala.

In Java:

Let’s assume that we are learning Java and want to confirm this with our own “Hello World” program. In Java, you would do something like the following:

public class HelloWorld{
    public static void main (String [] args){
        System.out.println("Hello World!");
    }
}

For someone new to Java, or to a programmer, this introduces a lot of new concepts, such as a class, public, static and so on, that need to be figured out before a full understanding is reached.

Contrast this to the Scala equivalent.

In Scala:

scala> println("Hello World")

That’s it – nothing more, nothing less. Scala is so minimalistic and unceremonious that you do not even need to type the semicolon at the end of every program statement, which is the case with Java (and other languages like C++ and C#).

Behind the Scenes:

Under the hood, the Scala compiler does a lot of work for you so that the “Hello World” program can run. The compiler actually writes a class with a “public static void main” method and inserts your code in the class, compiles it and sends it across to JVM to run it.

This type of “do it for you” approach is very evident in Scala as it constantly saves you time during development.

Scala Type System Variables & Values

The Type Systems of Scala and Java – a discussion

Both Scala and Java are examples of statically typed languages.

A programming language is said to use static typing when type checking is performed during compile-time – it is not done at run-time.

In static typing, types are associated with variables, not values. A dynamically typed language has the majority of its type checking performed at run-time – it is not done at compile-time.

Some people place Scala into the statically typed category because Scala has static typing. While this is true, Scala has most of the flexibility and syntactic economy of several languages, such as Ruby and Python, and the power of static typing, to boot.

Data Types:

In Java:
Each variable in Java has a data type and can be mainly classified into two groups:

  • Primitive data types – such int, char, double, etc.
  • Object references – both user-defined and built-in, such as String

Note that all user-defined classes in Java implicitly extend the java.lang.Object class.

In Scala:
In sharp contrast to Java, all values in Scala are objects; this includes numerical values and functions. Since Scala is class-based, all values are instances of a class. The diagram below pictorially illustrates the nature of the class hierarchy.

image33

Scala Class Hierarchy : scala.Any, the superclass of all classes, has two direct subclasses.

These are scala.AnyVal and scala.AnyRef and they represent two different class worlds: value classes and reference classes.

All value classes are predefined; they can be related to the primitive types of languages, like Java.

The rest of the classes define reference types. User-defined classes always (indirectly) subclass scala.AnyRef. The trait scala.ScalaObject is implicitly extended by all user-defined classes.
Classes from the infrastructure on which Scala is running (e.g., the Java runtime environment) do not extend scala.ScalaObject.

scala.AnyRef corresponds to java.lang.Object if Scala is used in the context of a Java runtime environment.

Declaration and type-inference in Scala

Static typing has to do with the explicit declaration (or initialization) of variables before they are employed. A static type is a property of a part of the program that can be statically proven (static means “without running it”). In a statically typed language, every expression has a type, whether it is written or not.

In Java:

int x = a * b + c - d;

a,b,c,and d have types, a * b has a type, a * b + c has a type and a * b + c -d has a type.

In Scala:
Above, we’ve annotated x with a type (int). In Scala this is unnecessary. You can do the equivalent with the following code.

y = a * b + c - d

As you can see, Scala code in general is less verbose compared to Java (and many other languages).

Scala can achieve this because of its type inference.

In general, it is a characteristic of functional programming languages. Many programming tasks are made easier as as result of being able to infer types automatically. This leaves the programmer free to omit type annotations while still permitting type checking.

This allows the developer to focus more on solving the problems at hand with the code, rather than writing a lot of extra verbose code to keep the compiler happy.

In Scala, the general expression for initializing a variable is as follows. The colon and type are optional.

val name:type = initialization

For example:

val x = 10
val y = 15.78

Could equally be typed as:

val x:Int = 10
val y:Double = 15.78

When you explicitly specify the type, you tell Scala that x is an Int and y is a Double, rather than letting it automatically infer the type.

Let’s try out some code in IntelliJ

Type the following commands in the worksheet in IntelliJ one line at a time, and look at the results on the right-hand side of the screen as you do so.

image34

The Int data type is an integer, which means it only holds whole numbers. You see this on line 1. To hold fractional numbers, as on line 2, use a Double. A Boolean data type, as on line 4, only holds the two special values, true and false.

A String holds a character sequence. You can assign a value using a double-quoted string as on line 5, or if you have many lines and/or special characters, you surround them with triple-double-quotes, as on lines 6 to 8 (this can be called a multi-line string).

Scala uses type inference to figure out what you mean when you mix types. When you mix Ints and Doubles using addition, for example, Scala decides the type to use for the resulting value. Try the following:

val n = 1 + 1.2

Note how Scala figures out that n is of type double.

value vs. var

You can decide whether to make a variable immutable or mutable. Immutable is read-only, whereas mutable means read-write. Immutable variables are declared with the keyword val.

val distance:Double = 22

Here distance has been initialized to a value during its declaration. As it has been declared as a val, distance cannot be reassigned to a new value. Any attempt to do will result in a reassignment to val error. Let us consider an Array being declared as val.

val myarr:Array[String]=new Array(6)

Here myarr reference cannot be changed to point to a different Array, but the array itself can be modified internally. In other words, the contents/elements of the array can be modified.

myarr = new Array(5) //This will give a reassignment to val error.
myarr (0)="Scala" //This does not give an error.

Note that val variables must be initialized (or defined) during declaration.

Mutable variables are declared with the keyword var. Unlike val, “var” can be reassigned to different values or point to different objects. But they, too, have to be initialized at the time of declaration.

The output to the lines are shown in bold.

var temp:Int=22
age: Int=22
temp =35
age: Int=35

There is an exception to this rule when initializing vals and vars.

When they are used as constructor parameters, they will be initialized when the object is instantiated. Also, derived classes can override vals declared inside the parent classes.

Scala and the Usage of Semicolons

In Scala, semicolons can be used to separate statements and expressions similarly to what is done in Java, C, PHP, and a number of other languages.

However, in most cases, Scala behaves like many scripting languages in treating the end of the line as the end of a statement or an expression.

When a statement or expression is too long for one line, Scala can usually infer when you are continuing on to the next line, as shown in this example:

image35

If you want to put more than one statements on the single line, use the semicolon to separate them like you see below.

str = "hello world"; println (str)

Statements, Expressions and Operators

Like many other languages, Scala distinguishes between expressions and statements.

Statements in Scala

A statement is something that does not return a value or produce a result. For example:

class MyClass(val value: String)

Class definitions are statements, since they do not produce a value.

Expressions in Scala

By contrast, expressions return a value that informs the caller of the result of the operation.

An example of simple expression that returns a String:

val str = "Hi , there!"

An example of multi-line expression that returns a Int:

image36

Note that the scope of variables i1, j1 is limited to the curly brackets and is not available beyond outside of the brackets’ scope.

What if an expression doesn’t produce a result?

Type this into the Scala worksheet in IntelliJ.

val z = println(105)
Output:
105
z: Unit = ()

The call to println doesn’t produce a value, so the expression doesn’t either. Scala has a special type for an expression that doesn’t produce a value: it is called a Unit.

Conditional Expressions

An if statement is an example of a conditional expression. An if statement can be followed by an optional else if…else statement, which is very useful to test various conditions.

image37

Compound Expressions

Almost everything in Scala is an expression. Expressions can contain one line of code, or multiple lines of code surrounded (which then need curly brackets).

A compound expression can contain any number of other expressions, including other curly-bracketed expressions. Here is an example:

image09

Some constructs that are represented as statements in other languages are actually expressions in Scala. For example:

  • if-else structures are statements in most languages, but are expressions in Scala. The type of an if-else expression is the common supertype of all the branches.
  • while loops are expressions in Scala that return a Unit. Similarly, for loops (not to be confused with for expressions) also return Unit.
  • throw, used to generate exceptions, are expressions of type Nothing, which is a bottom type to all types in Scala.

Operators

An operator is a symbol that tells the compiler to perform specific mathematical or logical manipulations. Scala is rich in built-in operators and provides following type of operators:

  • Arithmetic Operators (such as +, -, *)
  • Relational Operators (such as ==, >, <)
  • Logical Operators (such as &&, ||, !)
  • Bitwise Operators (such as &, >>, <<)
  • Assignment Operators (such as =, +=, *=)

Operator Overloading

Scala also allows operator overloading. Operators are typically things such as +, -, and !.

As a programmer, you would frequently use operators to perform arithmetic on numbers, or for manipulating Strings. Operator overloading, just like method overloading, allows you to redefine their behaviour for a particular type, and give them meaning for your own custom classes.

Loops

Scala programming language provides the following types of loops to handle looping requirements:

  • while Loop
  • do…while Loop
  • for…Loop

Below is an example of all three.

while Loop – See the screenshot below.

image10

do-while loop – See the screenshot below.

image11

for-loop – See the screenshot below.

image12

Breaking out of a for-loop – See the screenshot below.

image13

Functional Programming in Scala

Scala is a hybrid object-functional language: it supports both object-oriented and functional programming paradigms.

Haskell and ML have heavily influenced the Scala design. Yet Scala also borrows heavily from familiar object-oriented concepts Java (and many other) programmers love.

You get the best of both worlds with Scala – the ability to use both.

In Scala it is possible to have nested functions (functions within functions), a function returning a function, a function taking a function as parameters, and so on.

The functional programming paradigm was explicitly created to support a purely functional approach to problem solving.

You could say that functional programming is a form of declarative programming. This is the opposite of languages such as C++, Java, C# and even Visual Basic, which are primarily designed for imperative (procedural) programming.

An imperative approach to programming requires that the developer write code that needs to describe in exact detail the steps that the computer must take to accomplish the goal. Algorithmic programming is another term for this approach to development.

Functional programming differs in that you compose the problem to be solved as a set of functions to execute. This is achieved by carefully defining the input to each function as well as what the function returns.

Let’s look at how we would do both styles of development in Java (functional programming for Java was introduced in release 8 of Java), and then show the equivalent code in Scala.

In this example, we will add some integers to a List.

Java example code:

image14

In the first example above, Java code – AddElementsOfList.java, and specifically lines 17 – 21, we used an imperative style of programming to achieve our goal.

  • Our code explicitly tells the program how to do or go about things
  • Our code deals with mutating objects

The code above is very expressive, declares several variables, uses a for-loop, had to iterate over the List and dealt with mutating variables.

It’s a lot of code for a relatively simple task.

In the world of functional/declarative style of programming, the goal when we develop is as follows:

  • Focus on what to achieve in our code and ask the language to decide how to achieve the target
  • Deal with non-mutating objects

The equivalent Scala code using functional programming is shown in the code below:

image15

First, the reduce function (a Scala library function) adds 1 (first list element) and 2 to get 3.

That becomes the sum, which is added to the 3 to get 6, which becomes the new sum.

This is added to 4 to get 10, which becomes the final sum.

At this point, reduce then stops because there is nothing else to add, returning the final sum of 10.

Notice that reduce takes a function (lambda expression or anonymous function).

The expression (listElement, sum) => listElement + sum is a lambda.

The expression (listElement, sum) means that listElement and sum are the parameters of the lambda.

listElement + sum is the function body of the lambda , both separated by =>.

The function body is executed with each iteration of the list elements. This function has no name (hence it’s anonymous), and the type of parameters and return type are automatically inferred by Scala runtime.

The above code is much less verbose (only 2 lines, leaving out the first line which creates the List) compared to the Java code.

Scala Functions, and the Return statement

A Scala function definition has the following form:

def functionName ([list of parameters]) : [return type] = {
   function body
   return [expr]
}

Here are a few basic facts about Scala functions:

  • def is keyword indicating that it is a function.
  • return type could be any valid scala data type, and the list of parameters would be a list of variables separated by comma; the list of parameters and return type are optional.
  • Much like in Java, a return statement can be used (not mandatory, as you can see in the screenshot below) along with an expression in case function returns a value.
  • Methods are implicitly declared abstract if you omit the equals sign and method body. The enclosing type is then itself abstract.
  • A function which does not return anything can return Unit, which is equivalent to void in Java and indicates that function does not return anything. The functions which do not return anything in Scala are called procedures.

Example of a Function with parameters

Here we have a simple function that takes two string parameters and returns a string.

image16

return statement conundrum:
Generally the return statement is optional in Scala. However, in certain cases, such as a recursive function, Scala requires a return or result type.

In the example below, tryfactorial is a recursive function that calculates a factorial for a given number passed to the function.

image17

You can see the error above where Scala complains that it needs a return type for the recursive function factorial.

In this case, the Scala interpreter actually means that it cannot go multiple levels to find what your return type is, and hence it needs you to indicate the return type.

Adding the type (a BigInt, in our example) will resolve the errors, and you then get clear output from the interpreter on the right pane of the Scala worksheet. See the screenshot below:

image18

Mutability of Function Parameters

Java allows you to change the value of function parameters, as you can see in the code sample below.

image00

In the code example above, the Java compiler does not complain even though the parameter valueToChange was modified in the method (of course, this can be disabled in Java using a final).

The Scala compiler, on the other hand, will not allow this, as you can see below. In other words, function parameters are immutable in Scala.

image01

Why does Scala does not allow you to change the value of the function arguments?

This actually corrects a bad design decision in Java. Often, unintended bugs get introduced into code when a developer inadvertently modifies the parameter at a certain point, resulting in a frustrating time debugging and finding the error.

Scala nips this problem in the bud by not allowing a function parameter to be changed.

Scala Classes, Constructors, Getters & Setters

Here is sample Java class:

image02

And here is a sample in Scala:

image03

Let’s see what is the same and what is different with classes in Java and Scala.

  • Similarities first – as you can see, the same keywords are there, such as class and this; brackets usage is similar; and there is a somewhat similar way of overloading constructors.
  • Constructors, though, require special mention for their differences along with other differences, such as getters and setter methods and access modifiers in Scala.
  • Constructor (line 1): Scala has a concept of Class arguments. When you create a new object, you typically want to initialize it by passing some information. You do this using class arguments. This is part of the “Primary Constructor” in Scala.
  • Auxiliary Constructor (line 18 – 20): We can also use constructor overloading by creating multiple constructors. The name is “overloaded” here because you’re making different ways to create objects of the same class. To create an overloaded constructor, you define a method (with a distinct argument list) called this (a keyword). Overloaded constructors have a special name in Scala: auxiliary constructors.
  • override (line 9) is a key word Scala uses for overriding, though that is not required in Java.
  • Getters & Setters: Unlike in Java, there is no typical getter/setter method a programmer needs to create in Scala, and you can get/set member variables at will. Scala does create getters/setters for you automatically. However, there is a catch here, which will be evident when we discuss it a little later in this tutorial.

The primary constructor of a Scala class consists of:

  • The parameters of constructor
  • Statements and expressions executed in the body of the class
  • Methods called in the body of the class

Fields declared in the body of a Scala class are handled in a manner similar to Java, whereby they are assigned when the class is first instantiated.

Since the methods in the body of the class are part of the primary constructor, you’ll be able to see the output from the println statements at the beginning and end of the class declaration when an instance of a Customer class is created, along with the call to the printAddress method near the middle of the class as below:

Inside primary constructor
Address = Udemy Australia
still in the constructor
cust: Customer = Cliff Richard has order value of 1850.0
92.5
res0: Unit = ()

The process of declaring a primary constructor in Scala is vastly different.

In the example shown, the two constructor arguments, fullName and orderValue, are defined as var fields, which means that they’re variable, or mutable; they can be changed after they’re initially set.

Because the fields are mutable, Scala automatically generates both accessor and mutator methods for them.

As a result, given an instance cust of type Customer, you can change the values like this:

cust.fullName = "Scott Ambler"
cust.orderValue = 1850.85

and you can access them like this:

println(cust.fullName)
println(cust.orderValue)

Because the age field is declared as a var, it’s also visible, and can be mutated and accessed:

cust.age = 30
println(cust.age)

The field address is declared as a private val, which is like making it private and final in a Java class. Hence, it can’t be accessed directly by other objects, and its value can’t be mutated.

When you call a method in the body of the class—such as the call near the middle of the class to the printAddress method—that method call is also part of the constructor.

Anything other than method declarations, that is defined within the body of the class, is a part of the primary class constructor. Since auxiliary constructors must always call a previously defined constructor in the same class, they will also execute the same code, provided they exist.

A special note about getters and setters in Scala

Even though Scala under the hood creates getter and setters for mutable variables (declared as var), what about if the variable is a private and we still want to access the variable in a manner as we did earlier (where we described Customer class) like accessing the property directly? Here is the class and corresponding code screenshot:

image04

What is the above code doing? It’s a little cryptic.

First, the variable “age” is prepended with an “_” (underscore) and then made private with the private keyword. Note that “_age” is the variable for which we will be creating a getter and a setter. Next, the getter is added by the line:

def age = _age

This code simply defines a method called “age” and returns the “_age” variable. Scala doesn’t require the return keyword, but it would have just as easily been written as:

def age = return _age

In addition to not requiring the return keyword, Scala doesn’t make it mandatory to use the curly brackets around a method body if the expression body is only a single line. Also, the data types work with Scala’s type inferencing capabilities.

Next, a setter had to be added to set the private variable, since you cannot set it directly as you would do otherwise.

def age_= (value:Int):Unit = _age = value

This above line requires explanation. First, the method name is “age_=”.

The underscore (_) is a special character in Scala. The part (value:Int) is the value and type of parameter. The :Unit part means that it does not return anything. It could be equated to something like void in Java.

The remaining code is setting the “_age” variable to value of the setter’s argument (“value”).

These getters and setters allow the method to be used in the same way as directly accessing the public property. The line below (line 11 in screenshot) sets the _age variable to 99 (note we use “.age” and not “._age”).

emp.age = 99 //setter

But where are the parentheses in this supposed method call? Parentheses are usually optional in Scala. The previous line could just as easily been written as:

emp.age =(99)
// OR
emp.age_=(99)

Line 12 (in screenshot, also pasted below) does the job of getting the value and printing it.

println(emp.age) //getter

Inheritance in Scala

There is great deal of similarity between inheritance in Scala and Java. In Scala, overriding aspects are more detailed, since there are not just methods to override but also vals and vars. There are a few restrictions here, namely:

  • Overriding classes must use the override modifier. In Java, an @Override annotation is used to enforce overriding. Scala must use the override modifier.
  • Super class constructors cannot be directly invoked by Auxiliary constructors. They only can invoke the primary constructor which, in turn, would invoke the Super class constructor.

Class inheritance, as in most object-oriented languages, shares similarity with biological inheritance. It’s saying, “I want to make a new class from an existing class, but with some additions and modifications.”

The extends keyword is used by the subclass to inherit from a base class. The terms base class and derived class, or parent class and child class, or superclass and subclass are synonymous.

Let us take a concrete example – see the screenshot below:

image05

The show method takes a Vehicle as an argument, and naturally you call it with a Vehicle, as can be seen. However, one can also call the show method with a Car or a MotorBike.

Even though the latter two are distinct types, the above code works because inheritance guarantees that anything that inherits from Vehicle is a Vehicle.

All code that acts upon objects of these derived classes knows that Vehicle is at their core, so any methods and fields in Vehicle will also be available in its children.

Inheritance creates opportunities for code simplification and reuse.

When you inherit, the derived-class constructor must call the primary base-class constructor; if there are auxiliary (overloaded) constructors in the base class, one may optionally call one of those instead.

The derived-class constructor must pass the appropriate arguments to the base-class constructor.

As an example, when Car inherits from Vehicle, it passes the appropriate arguments to the primary Vehicle constructor.

Notice that it also adds its own val argument (wiperType) – the number, type or order of the arguments in the base class does not matter.

The only requirement is to provide the correct base-class arguments.

In a derived class, one may call any of the overloaded base-class constructors via the derived-class primary constructor by providing the necessary constructor arguments in the base-class constructor call.

These can be seen in the definitions of Car and MotorBike. Each uses a different base-class constructor of the base class Vehicle. You can’t call base-class constructors inside of overloaded derived-class constructors.

A Scala object

Scala’s object keyword defines something that looks roughly like a class, except you can’t create instances of an object – only one instance exists. By creating an object, one can logically group methods and fields. Let us see a simple object as follows:

image06

Companion object

The object keyword allows one to create a companion object for a class. The difference between an ordinary object and a companion object is that the latter has the same name as the name of a class. Hence, an association between the companion object is created.

The screenshot example below shows that anyVal has only a single piece of storage (no matter how many instances are created) and that x1 and x2 are both accessing that same memory. To access elements of the companion object from methods of the class, you must give the name of the companion object (AnyObject), as in lines 8 and 9.

image07

Scala Traits

A Trait is a different approach to creating classes: it allows inheritance in small chunks rather than all in a single go, which is what happens when creating a subclass.

Traits are small, logical concepts that allow one to easily “mix in” ideas to create a class.

For this reason, they are often called mixin types. Trait typically represent a singular concept such as Color, Softness, Brittleness, etc.

Important facts about Trait

  • A trait definition looks like a class, but uses the trait keyword instead of class.
  • To combine traits into a class, you always begin with the extends keyword, then add additional traits using the with keyword.
  • A class can only inherit from a single concrete or abstract base class, but it can combine as many traits as you want. If there is no concrete or abstract base class, you still start with the extends keyword for the first trait, followed by the with keyword for the remaining traits.
  • A freestanding trait cannot be instantiated; a Trait does not have a full-fledged constructor.
  • If any of the fields and/or methods that a class extends lack definition or implementation, then Scala will insist that you include the abstract keyword.

Here we have some of the simplest possible Trait and Class definitions:

trait Hardness
trait Brittleness
trait Color
class Material
class Metal extends Material with Hardness
 with Texture with Hardness
class Plastic extends Brittleness with Color
 with Hardness

Traits can inherit from abstract or concrete classes. Traits can also inherit from other traits – see the screenshot below. Here are example of some traits that have defined some member variables:

image08

Final Scala Demo Program

Let’s put everything we have learned in this tutorial into a program.

Because of the size of the code, it is not practical to show a screenshot. So, just type this code into the Scala worksheet in IntelliJ.

Note that there are detailed comments explaining core concepts.


class Person (
               val firstName: String,
               val lastName: String,
               val age: Int,
               val vocation: String
               ) {

  def fullName = firstName + " " + lastName
  def birthPlace: Unit = println("I was born in this universe")
  def introduce (informal: Boolean): String = {
    if (informal)
      "Hi, I'm " + firstName + "!"
    else
      "Hello, my name is " + fullName + ". I'm a " + vocation + "."
  }

}

trait Worker {
  def selfIntroduction: String
}

class Musician (
                 firstName: String,
                 lastName: String,
                 age: Int,
                 val speciality: String,
                 val favoriteInstrument: String) 
  extends Person(firstName, lastName, age, "musician") with Worker {

  def selfIntroduction =
    "As a " + vocation + ", I am a " + speciality + 
      " who likes to play the Instrument " + favoriteInstrument + "."
  override def birthPlace : Unit =  println("I was born in Europe")
}

class Student (school: String, subject: String) extends Worker {
  def selfIntroduction = "I'm studying " + subject + " at " + school + "!"
}


object Surgeon{
  var count_of_surgeons : Int = 0
}


class Surgeon (
                          firstName: String,
                          lastName: String,
                          age: Int,
                          val speciality: String,
                          favoriteTool: String) 
  extends Person(firstName, lastName, age, "Surgeon") with Worker {

  def selfIntroduction =
    "As a " + vocation + ", I work on " + speciality +
      ". Much of my surgical operartions are done with " + favoriteTool + "."
  def incrementSurgeonCount:Int = 
  {Surgeon.count_of_surgeons +=1; return Surgeon.count_of_surgeons}
}


//here’s how we can create Jack Carter now who is a Person
val jackCarter = new Person("Jack", "Carter", 37, "musician")

//we can now access the fields and functions

jackCarter.age
jackCarter.introduce(true)

val jillBrown = new Person("Jill", "Brown", 34, "computer scientist")
val johnDoe = new Person("John", "Doe", 43, "philosopher")
val harryPotter = new Person("Harry", "Potter", 28, "mathematician")
val johnBaldridge = new Person("John", "Baldridge", 43, "trucker")

//These above Person objects can now be aggregated into a list
// together, giving us a List[Person]
// that allows mapping to retrieve specific values, like first
// names and ages, and
// performing computations like calculating the average age of
// the individuals in the list.

val people = List(jackCarter, jillBrown, johnDoe, harryPotter)
people.map(person => person.firstName)
people.map(person => person.age)
people.map(person => person.age).sum/people.length.toDouble

//sorting according age can be done now

val ageSortedPeople = people.sortBy(_.age)
ageSortedPeople.map(person => person.fullName + ":" + person.age)

//grouping people by first name, last name, etc.

people.groupBy(person => person.firstName)
people.groupBy(person => person.lastName)

//With this, we can have all the Johns greet us.

people.groupBy(person => person.firstName)("John").foreach(john => println(john.introduce(true)))

//example of a standalone object

object JoelAbrahamsson extends Person("Joel", "Abrahamsson", 43, "musician")
JoelAbrahamsson.introduce(true)

//The Musician class has its own parameter list: some
// of these, like firstName, lastName, and age,
// are passed on from Person, and there are new
// parameter fields speciality and favoriteInstrument.

val cliffRichard = new Musician("Cliff", "Richard", 83, "guitarist", "guitar")
cliffRichard.selfIntroduction
cliffRichard.age
cliffRichard.introduce(true)
cliffRichard.favoriteInstrument

val anyStudent = new Student("The University of California, Berkeley", "economics")
anyStudent.selfIntroduction

//Notice that the parameters school and subject
// were not "val" in the Student definition
// which means that they are not member fields
// of the Student class. Hence, attempting to
// access the value provided for school for
// anyStudent fails as you can see by uncommenting
//the line of code immediately below

//anyStudent.school  ----fails

val billyBowden = new Surgeon("Billy", "Bowden", 44, "heart transplant", "scalpel")
billyBowden.selfIntroduction

//Notably, the speciality field of Surgeon is
// disconnected from that of Musician, so there
// is no particular expectation of consistency
// of use across the two. So, what happens if we
// put cliffRichard and billyBowden in a List together

val professionals = List(cliffRichard, billyBowden)

//we can treat all of the elements of
// professionals as Persons, e.g., accessing
// their vocation (which is a member field of Person).

professionals.map(prof => prof.vocation)

//We can treat each element of the list as
// a Person and a Worker, e.g., printing out their
// fullName (from Person) and their
// selfIntroduction (from Worker).

professionals.foreach(prof => println(prof.fullName + ": " + prof.selfIntroduction))

//However, access to fields and functions
// that are specific to Muscian or Surgeon,
//such as favoriteTool from Surgeon is not
// possible - try to run the code below
//by uncommenting

//professionals.map(prof => prof.favoriteTool) ---this fails