SCALA TOUR - Learn Scala for Java Developers (2015)

Learn Scala for Java Developers (2015)

I. SCALA TOUR

Welcome to Learn Scala for Java Developers. This book will help you transition from programming in Java to programming in Scala. It’s designed to help Java developers get started with Scala without necessarily adopting all of the more advanced functional programming idioms.

Scala is both an object-oriented language and a functional language and although I do talk about some of the advantages of functional programming, this book is more about being productive with imperative Scala than getting to grips with functional programming. If you’re already familiar with Scala but are looking to make the leap to pure functional programming, this probably isn’t the book for you. Check out the excellent Functional Programming in Scala by Paul Chiusano and Rúnar Bjarnaso instead.

The book often compares “like-for-like” between Java and Scala. So, if you’re familiar with doing something a particular way in Java, I’ll show how you might do the same thing in Scala. Along the way, I’ll introduce the Scala language syntax.

The Scala Language

Scala is both a functional programming language and an object-oriented programming language. As a Java programmer, you’ll be comfortable with the object-oriented definition: Scala has classes, objects, inheritance, composition, polymorphism — all the things you’re used to in Java.

In fact, Scala goes somewhat further than Java. There are no “non”-objects. Everything is an object, so there are no primitive types like int and no static methods or fields. Functions are objects and even values are objects.

Scala can be accurately described as a functional programming language because it meets some fairly formal criteria. For example, it allows you both to define pure functions and use higher-order functions.

Pure Functions

Pure functions aren’t associated with objects, and work without side effects. A key concern in Scala programming is avoiding mutation. There’s even a keyword to define a fixed variable, a little like Java’s final: val.

Pure functions should operate by transformation rather than mutation. That is to say, a pure function should take arguments and return results but not modify the environment it operates in. This purity of function is what enables referential transparency.

Higher-Order Functions

Functional languages should treat functions as first-class citizens. This means they support higher-order functions: functions that take functions as arguments or return functions and allow functions to be stored for later execution. This is a powerful technique in functional programming.

Scala’s Background

Scala started life in 2003 as a research project at EPFL in Switzerland. The project was headed by Martin Odersky, who’d previously worked on Java generics and the Java compiler for Sun Microsystems.

It’s quite rare for an academic language to cross over into industry, but Odersky and others launched Typesafe Inc., a commercial enterprise built around Scala. Since then, Scala has moved into the mainstream as a development language.

Scala offers a more concise syntax than Java but runs on the JVM. Running on the JVM should (in theory) mean an easy migration to production environments; if you already have the Oracle JVM installed in your production environment, it makes no difference if the bytecode was generated from the Java or Scala compiler.

It also means that Scala has Java interoperability built in, which in turn means that Scala can use any Java library. One of Java’s strengths over its competitors was always the huge number of open source libraries and tools available. These are pretty much all available to Scala too. The Scala community has that same open source mentality, and so there’s a growing number of excellent Scala libraries out there.

The Future

Scala has definitely moved into the mainstream as a popular language. It has been adopted by lots of big companies including Twitter, eBay, Yahoo, HSBC, UBS, and Morgan Stanley, and it’s unlikely to fall out of favour anytime soon. If you’re nervous about using it in production, don’t be; it’s backed by an international organisation and regularly scores well in popularity indexes.

The tooling is still behind Java though. Powerful IDEs like IntelliJ’s IDEA and Eclipse make refactoring Java code straightforward but aren’t quite there yet for Scala. The same is true of compile times: Scala is a lot slower to compile than Java. These things will improve over time, and on balance, they’re not the biggest hindrances I encounter when developing.

Installing Scala

There are a couple of ways to get started with Scala.

1. You can run Scala interactively with the interpreter,

2. run shorter programs as shell scripts, or

3. compile programs with the scalac compiler.

The Scala Interpreter

Before working with an IDE, it’s probably worth getting familiar with the Scala interpreter, or REPL.

Download the latest Scala binaries (from http://scala-lang.org/downloads) and extract the archive. Assuming you have Java installed, you can start using the interpreter from a command prompt or terminal window straight away. To start up the interpreter, navigate to the exploded folder and type1:

bin/scala

You’ll be faced with the Scala prompt.

scala> _

You can type commands followed by enter, and the interpreter will evaluate the expression and print the result. It reads, evaluates and prints in a loop so it’s known as a REPL.

If you type 42*4 and hit enter, the REPL evaluates the input and displays the result.

scala> 42*4

res0: Int = 168

In this case, the result is assigned to a variable called res0. You can go on to use this, for example to get half of res0.

scala> res0 / 2

res1: Int = 84

The new result is assigned to res1.

Notice the REPL also displays the type of the result: res0 and res1 are both integers (Int). Scala has inferred the types based on the values.

If you add res1 to the end of a string, no problem; the new result object is a string.

scala> "Hello Prisoner " + res1

res2: String = Hello Prisoner 84

To quit the REPL, type:

:quit

Scala Scripts

The creators of Scala originally tried to promote the use of Scala from Unix shell scripts. As competition to Perl, Groovy or bash scripts on Unix environments it didn’t really take off, but if you want to, you can create a shell script to wrap Scala:

1 #!/bin/sh

2 exec scala "$0" "$@"

3 !#

4 object HelloWorld {

5 def main(args: Array[String]) {

6 println("Hello, " + args.toList)

7 }

8 }

9 HelloWorld.main(args)

Don’t worry about the syntax or what the script does (although I’m sure you’ve got a pretty good idea already). The important thing to note is that some Scala code has been embedded in a shell script and that the last line is the command to run.

You’d save it as a .sh file, for example hello.sh, and execute it like this:

./hello.sh World!

The exec command on line 2 spawns a process to call scala with arguments; the first is the script filename itself (hello.sh) and the second is the arguments to pass to the script. The whole thing is equivalent to running Scala like this, passing in a shell script as an argument:

scala hello.sh World!

scalac

If you’d prefer, you can compile .scala files using the Scala compiler.

The scalac compiler works just like javac. It produces Java bytecode that can be executed directly on the JVM. You run the generated bytecode with the scala command. Just like Java though, it’s unlikely you’ll want to build your applications from the command line.

All the major IDEs support Scala projects, so you’re more likely to continue using your favorite IDE. We’re not going to go into the details of how to set up a Scala project in each of the major IDEs; if you’re familiar with creating Java projects in your IDE, the process will be very similar.

For reference though, here are a few starting points.

· You can create bootstrap projects with Maven and the maven-scala-plugin.

· You can create a new Scala project directly within IntelliJ IDEA once you’ve installed the scala plugin (available in the JetBrains repository).

· Similarly, you can create a new Scala project directly within Eclipse once you have the Scala IDE plugin. Typesafe created this and it’s available from the usual update sites. You can also download a bundle directly from the scala-lang or scala-ide.org sites.

· You can use SBT and create a build file to compile and run your project. SBT stands for Simple Build Tool and it’s akin to Ant or Maven, but for the Scala world.

· SBT also has plugins for Eclipse and IDEA, so you can use it directly from within the IDE to create and manage the IDE project files.

1. If you don’t want to change into the install folder to run the REPL, set the bin folder on your path.

Some Basic Syntax

Defining Values and Variables

Let’s look at some syntax. We’ll start by creating a variable:

val language: String = "Scala";

We’ve defined a variable as a String and assigned to it the value of “Scala”. I say “variable”, but we’ve actually created an immutable value rather than a variable. The val keyword creates a constant, and language cannot be modified from this point on. Immutability is a key theme you’ll see again and again in Scala.

If we will want to modify language later, we can use var instead of val. We can then reassign it if we need to.

var language: String = "Java";

language = "Scala";

So far, this doesn’t look very different from Java. In the variable definition, the type and variable name are the opposite way round compared to Java, but that’s about it. However, Scala uses type inference heavily, so Scala knows that the var above is a string, even if we don’t tell it.

val language = "Scala";

Similarly, it knows that the expression is finished without needing to tell it explicitly with the semicolon. So we can drop that too.

val language = "Scala" // no semicolon

You only need to add semicolons when you use multiple expressions on the same line; otherwise things get too complex for the compiler.

Operator precedence is just as you’d expect in Java. In the example below, the multiplication happens before the subtraction.

scala> val age = 35

scala> var maxHeartRate = 210 - age * .5

res0: Double = 191.5

Defining Functions

Function and method definitions start with the def keyword, followed by the signature. The signature looks similar to a Java method signature but with the parameter types the other way round again, and the return type at the end rather than the start.

Let’s create a function to return the minimum of two numbers.

def min(x: Int, y: Int): Int = {

if (x < y)

return x

else

return y

}

We can test it in the REPL by calling it:

scala> min(34, 3)

res3: Int = 3

scala> min(10, 50)

res4: Int = 10

Note that Scala can’t infer the types of function arguments.

Another trick is that you can drop the return statement. The last statement in a function will implicitly be the return value.

def min(x: Int, y: Int): Int = {

if (x < y)

x

else

y

}

Running it the REPL would show the following:

scala> min(300, 43)

res5: Int = 43

In this example, the else means the last statement is consistent with a min function. If I forgot the else, the last statement would be the same regardless and there would be a bug in our implementation:

def min(x: Int, y: Int): Int = {

if (x < y)

x

y // bug! where's the else?

}

It always returns y:

scala> min(10, 230)

res6: Int = 230

If you don’t use any return statements, the return type can usually be inferred.

// the return type can be omitted

def min(x: Int, y: Int) = {

if (x < y)

x

else

y

}

Note that it’s the equals sign that says this function returns something. If I write this function on one line, without the return type and just the equals sign, it starts to look like a real expression rather than a function.

def min(x: Int, y: Int) = if (x < y) x else y

Be wary, though; if you accidentally drop the equals sign, the function won’t return anything. It’ll be similar to the void in Java.

def min(x: Int, y: Int) {

if (x < y) x else y

}

<console>:8: warning: a pure expression does nothing in statement position;

you may be omitting necessary parentheses

if (x < y) x else y

^

<console>:8: warning: a pure expression does nothing in statement position;

you may be omitting necessary parentheses

if (x < y) x else y

^

min: (x: Int, y: Int)Unit

Although this compiles okay, the compiler warns that you may have missed off the equals sign.

Operator Overloading and Infix Notation

One interesting thing to note in Scala is that you can override operators. Arithmetic operators are, in fact, just methods in Scala. As such, you can create your own. Earlier, we saw the integer age used with a multiplier.

val age: Int

age * .5

The value age is an integer and there is a method called * on the integer class. It has the following signature:

def *(x: Double): Double

Numbers are objects in Scala, as are literals. So you can call * directly on a variable or a number.

age.*(.5)

5.*(10)

Using the infix notation, you’re able to drop the dot notation for variables and literals and call:

age * .5

or, as another example:

35 toString

Remember, 35 is an instance of Int.

Specifically, Scala support for infix notation means that when a method takes zero or one arguments you can drop the dot and parentheses, and if there is more than one argument you can drop the dot.

For example:

35 + 10

"aBCDEFG" replace("a", "A")

It’s optional though; you can use the dot notation if you prefer.

What this means is that you can define your own plus or minus method on your own classes and use it naturally with infix notation. For example, you might have a Passenger join a Train.

train + passenger

There are not many restrictions on what you can call your functions and methods; you can use any symbol that makes sense to your domain.

Collections

Scala comes with its own immutable collection types as well as mutable versions. By default immutability is preferred, so we can create a list with the following:

val list = List("a", "b", "c")

And create a map with:

val map = Map(1 -> "a", 2 -> "b")

where the arrow goes from the key to the value. These will be immutable; you won’t be able to add or remove elements.

You can process them in a similar way to Java 8’s forEach and lambda syntax:

list.foreach(value => println(value)) // scala

which is equivalent to the following in Java:

list.forEach(value -> System.out.println(value)); // java

Like Java 8’s method reference syntax, you can auto-connect the lambda argument to the method call.

list.foreach(println) // scala

which is roughly equivalent to this Java:

list.forEach(System.out::println); // java

There are lots of other Scala-esque ways to process collections. We’ll look at these later, but the most common way to iterate is a for loop written like this:

for (value <- list) println(value)

which reads, “for every value in list, print the value”. You can also do it in reverse:

for (value <- list.reverse) println(value)

or you might like to break it across multiple lines:

for (value <- list) {

println(value)

}

Java Interoperability

I mentioned that you can use any Java class from Scala. For example, let’s say we want to create a Java List rather than the usual Scala immutable List.

val list = new java.util.ArrayList[String]

All we did was fully qualify the class name (java.util.ArrayList) and use new to instantiate it. Notice the square brackets? Scala denotes generics using [] rather than <>. We also didn’t have to use the parentheses on the constructor, as we had no arguments to pass in.

We can make method calls — for example, adding an element — just as you’d expect:

list.add("Hello")

or, using infix:

list add "World!"

Primitive Types

In Java there are two integer types: the primitive (non-object) int and the Integer class. Scala has no concept of primitives — everything is an object — so, for example, Scala’s integer type is an Int. Similarly, you’ll be familiar with the other basic types:

Byte

Short

Int

Long

Char

String

Float

Double

Boolean

Although Scala has its own richer types, typically they just wrap the Java types. When working with these basic types, nine times out of ten you won’t need to worry if you’re using Scala or Java types. Things are pretty seamless. For example, Scala has a BigDecimal type with a + method which means you can add two big decimals with much less code than in Java.

Compare the following Scala to Java:

// scala

val total = BigDecimal(10000) + BigDecimal(200)

// java

BigDecimal total = new BigDecimal(10000).add(new BigDecimal(200));

Scala hasn’t reimplemented Java’s BigDecimal; it just delegates to it and saves you having to type all that boilerplate.

Scala’s Class Hierarchy

Scala’s class hierarchy starts with the Any class in the scala package. It contains methods like ==, !=, equals, ##, hashCode, and toString.

abstract class Any {

final def ==(that: Any): Boolean

final def !=(that: Any): Boolean

def equals(that: Any): Boolean

def ##: Int

def hashCode: Int

def toString: String

// ...

}

Every class in Scala inherits from the abstract class Any. It has two immediate subclasses, AnyVal and AnyRef.

Fig. 1.1. Every class extends the `Any` class.

Fig. 1.1. Every class extends the Any class.

AnyVal

AnyVal is the super-type to all value types, and AnyRef the super-type of all reference types.

Basic types such as Byte, Int, Char, etc. are known as value types. In Java value types correspond to the primitive types, but in Scala they are objects. Value types are all predefined and can be referred to by literals. They are usually allocated on the stack but are allocated on the heap in Scala.

All other types in Scala are known as reference types. Reference types are objects in memory (the heap), as opposed to pointer types in C-like languages, which are addresses in memory that point to something useful and need to be dereferenced using special syntax (for example, *age = 64 in C). Reference objects are effectively dereferenced automatically.

There are nine value types in Scala:

Fig. 1.2. Scala's value types.

Fig. 1.2. Scala’s value types.

These classes are fairly straightforward; they mostly wrap an underlying Java type and provide implementations for the == method that are consistent with Java’s equals method.

This means, for example, that you can compare two number objects using == and get a sensible result, even though they may be distinct instances.

So, 42 == 42 in Scala is equivalent to creating two Integer objects in Java and comparing them with the equals method: new Integer(42).equals(new Integer(42)). You’re not comparing object references, like in Java with ==, but natural equality. Remember that 42 in Scala is an instance ofInt which in turn delegates to Integer.

Unit

The Unit value type is a special type used in Scala to represent an uninteresting result. It’s similar to Java’s Void object or void keyword when used as a return type. It has only one value, which is written as an empty pair of brackets:

scala> val example: Unit = ()

example: Unit = ()

A Java class implementing Callable with a Void object as a return would look like this:

// java

public class DoNothing implements Callable<Void> {

@Override

public Void call() throws Exception {

return null;

}

}

It is identical to this Scala class returning Unit:

// scala

class DoNothing extends Callable[Unit] {

def call: Unit = ()

}

Remember that the last line of a Scala method is the return value, and () represents the one and only value of Unit.

AnyRef

AnyRef is an actually an alias for Java’s java.lang.Object class. The two are interchangeable. It supplies default implementations for toString, equals and hashcode for all reference types.

There used to be a subclass of AnyRef called ScalaObject that all Scala reference types extended. However, it was only there for optimisation purposes and has been removed in Scala 2.11. (I mention it as a lot of documentation still refers to it.)

Fig. 1.3. Scala `Any`. The `ScalaObject` class no longer exists.

Fig. 1.3. Scala Any. The ScalaObject class no longer exists.

The Java String class and other Java classes used from Scala all extend AnyRef. (Remember it’s a synonym for java.lang.Object.) Any Scala-specific classes, like Scala’s implementation of a list, scala.List, also extend AnyRef.

Fig. 1.4. Scala's reference types.

Fig. 1.4. Scala’s reference types.

For reference types like these, == will delegate to the equals method like before. For pre-existing classes like String, equals is already overridden to provide a natural notion of equality. For your own classes, you can override the equals just as you would in Java, but still be able to use == in code.

For example, you can compare two strings using == in Scala and it would behave just as it would in Java if you used the equals method:

new String("A") == new String("A") // true in scala, false in java

new String("B").equals(new String("B")) // true in scala and java

If, however, you want to revert back to Java’s semantics for == and perform reference equality in Scala, you can call the eq method defined in AnyRef:

new String("A") eq new String("A") // false in scala

new String("B") == new String("B") // false in java

Bottom Types

A new notion to many Java developers will be the idea that a class hierarchy can have common bottom types. These are types that are subtypes of all types. Scala’s types Null and Nothing are both bottom types.

All reference types in Scala are super-types of Null. Null is also an AnyRef object; it’s a subclass of every reference type.

Fig. 1.5. The `Null` extends `AnyRef`.

Fig. 1.5. The Null extends AnyRef.

Both value and reference types are super-types of Nothing. It’s at the bottom of the class hierarchy and is a subtype of all types.

Fig. 1.6. `Nothing` extends `Null`.

Fig. 1.6. Nothing extends Null.

The entire hierarchy is shown in the diagram below. I’ve left off scala.Any to save space. Notice that Null extends all reference types and that Nothing extends all types.

Fig. 1.7. Full hierarchy with the bottom types `Null` and `Nothing`.

Fig. 1.7. Full hierarchy with the bottom types Null and Nothing.

ScalaDoc

Scala has ported the idea of JavaDoc and creatively called it ScalaDoc. Adding ScalaDoc to your Scala source works similarly to adding JavaDoc, and is done with markup in comments. For example, the following fragment in source code:

/** Returns `true` if this value is equal to x, `false` otherwise. **/

def ==(x: Byte): Boolean

…can be turned into the following fragment in HTML:

Fig. 1.8. Embedded ScalaDoc markup gets rendered in HTML.

Fig. 1.8. Embedded ScalaDoc markup gets rendered in HTML.

To see the documentation for the Scala API, head over to http://scala-lang.org/documentation. You’ll notice it is broadly similar to JavaDoc. You can see the classes along the left; they’re not grouped by package like in JavaDoc but they’re clickable to get more information.

Fig. 1.9. The basic ScalaDoc for `Char`.

Fig. 1.9. The basic ScalaDoc for Char.

A neat feature of ScalaDoc is that you can also filter the content. For example, you can show only methods inherited from Any.

If you’re interested in the hierarchy of a class, you can look at its super- and subtypes. You can even see a navigable diagram of the type hierarchy. For example, the type hierarchy diagram for Byte shows it is a subtype of AnyVal, and you can navigate up through the hierarchy by clicking on the diagram.

Fig. 1.10. ScalaDoc showing the type hierarchy diagram.

Fig. 1.10. ScalaDoc showing the type hierarchy diagram.

Language Features

On our tour we’ve seen some example syntax, walked through the class hierarchy, and briefly looked at ScalaDoc, but Scala offers heaps of other interesting language features.

In this chapter, we won’t really talk about syntax but we’ll discuss some of the things that make Scala an interesting and powerful language when working with source code, working with methods, and using its functional programming features.

Working with Source Code

Source Files. What you put in source files is much more flexible in Scala than in Java. There’s no restriction on what a .scala file contains. A file called Customer.scala might contain a class called Customer, but it doesn’t have to. Similarly, it might contain four classes, none of which are called Customer.

Packages. Packages are similar. Although they are essentially the same thing as in Java, classes in packages don’t have to live in folders of the same name like they do in Java. There are some differences in scoping; for example, there’s no protected keyword in Scala but you can use special syntax (variable[package]) to achieve the same thing.

Package Objects. Scala also has the idea of package objects. These are objects that you can put useful chunks of code in, for re-use within the package scope. They’re available to other classes in the package, and if someone imports that package, everything within the package object is available to them too. Libraries often use these to allow you to import all their classes in one go.

Import Alias. Imports are about the same as in Java but once you’ve imported a class in Scala, you can rename it within your class. In other words, you can create an alias for a class within your class. This can be useful when you’ve got a name clash, for example between libraries.

Type Aliases. Scala also supports type aliases. You can give an alias to a complex type definition to help clarify the intent. It’s similar to a structureless typedef or #define macro in C, or what’s called type synonyms in Haskell.

Traits. Although Scala has classes and objects, there is no “interface” keyword. Instead, there is the idea of a trait which is similar to an interface but can have methods. It’s somewhere between Java 8’s default methods and Ruby’s mixins.

Working with Methods

Generics. There’s better support for generic covariance and contravariance in Scala than Java. This means that you can be more general and more flexible in your method signatures when generic types are used as arguments.

class Stack[+A] {

def push[B >: A](b: B): Stack[B] = ...

}

Variable Arguments. When working with methods, Scala supports variable arguments or varargs just like Java. They look different (def sum(numbers: Int*)), but behave as you’d expect.

public add(String... names) // java

def add(names: String*) // scala

Named Method Arguments. Something Java doesn’t offer is named method arguments and default values. In Scala, you can call a method with its arguments out of order, as long as you name them. So, given the function def swap(first: Int, second: Int), you can call it explicitly, naming its arguments. Because they’re named, the compiler can work out which is which regardless of their position. So the following is fine:

swap(first = 3, second = 1)

swap(second = 1, first = 3)

Default Values. You can add a default value by using = after the parameter declaration. For example, def swap(first: Int, second: Int = 1). The second value will default to 1 if you leave it off when you call the function. You can still supply a value to override the default, and still use named parameters.

swap(3)

swap(3, 2)

swap(first = 3)

swap(first = 3, second = 1)

Lambdas. Scala supports lambdas or anonymous functions. You can pass function literals as arguments to methods and use a function signature as an argument in a method signature. So the test method below takes a function with no arguments which returns a Boolean.

def test(f: () => Boolean) = ...

When you call it, you can pass in a function literal as a parameter.

test(() => if (!tuesday) true else false)

As another example, you can create a function signature to represent a function from a String value to a Boolean like this:

def test(f: String => Boolean): Boolean = ...

and call it with a function literal like this:

test(value => if (value == "tuesday") true else false)

Functional Programming

Some other Scala features aimed more at functional programming include:

Pattern matching. This is a hugely powerful feature which at first blush looks similar to switches but can be used for much more.

For comprehensions. For comprehensions are subtly different than regular for loops, and are useful when working with functional constructs. When you first encounter them, they’ll look like an alternative syntax to Java’s for loop.

Currying. Although you can write your own currying functions in any language, Scala supports currying as a language feature. If you’re unsure what currying is, you probably don’t need to worry about it right now. See the currying chapter for more details.

Functional Literals. The language supports literals to represent some useful types like tuples. Popular Java functional libraries like totally-lazy or functional-java have these kinds of things; Scala just makes them easier to work with.

Recursion. Most languages support recursion, but Scala has compiler support for tail call optimisation, which means it can support recursive calls that would result in a stack overflow in languages like Java. The compiler can even perform some checks for you if you use the @tailrecannotation.

Summary

In this high-level tour, we talked about how Scala is both an OO language and a functional language. I mentioned that Scala in fact only has objects; there are no primitives, everything is an object.

We talked about Scala’s background, how it grew from an academic language to a commercially backed mainstream language, and how it runs on the JVM. This, in theory, lowers the barrier of adoption by making it easy to deploy to existing servers.

Running on the JVM also means there are plenty of libraries available to Scala, as Java interoperability is baked in. Despite some of the tools being behind and compilation time still being slow, Scala has been widely adopted and we see numerous big companies using it today.

We had a look at installing and running Scala. You saw the three ways Scala programs are typically run, and along the way were introduced to the Scala REPL.

We then moved on to a syntax tour and looked at some interesting language features.

In the syntax tour, we saw how to define variables and values, functions and methods, and saw how Scala reduces the boilerplate noise by inferring types and recognising terminating conditions like return and semicolons automatically.

We saw how infix notation means you can avoid the classical dot notation and importantly, we saw that method names can contain symbols. That’s how we’re able to use mathematical symbols naturally in code; they’re actually methods so we can override them and, using the infix notation, use them without the noisy dots and brackets.

We also worked with some collection types and saw a couple of basic ways to enumerate them: the foreach and for loop syntax. We saw how easy it is to work with Java objects; value types like Int and Boolean are basically the same in Scala and Java. We had a good look at how Scala represents types in its class hierarchy, and learnt how to look things up in the ScalaDoc.

In terms of language features, we looked at some interesting aspects of the language when working with source files and packages, methods and method arguments, as well as some features geared up for functional programming.

Fig. 1.11. Summary of Part I.

Fig. 1.11. Summary of Part I.