Basic Scala Syntax for Java Programmers

Categories: Java

IMPORTANT: Article still in progress!

Introduction

This page contains a quick summary of the syntax of the Scala programming language. These are mostly notes I made from an online Scala tutorial, a Scala book, and a Scala introductory video course; they have been posted here mostly as a reference for myself, and are not expected to be of particular use to anyone else. If you are learning Scala, then I would recommend reading the online tutorial yourself, and making your own notes!

Learning any language requires mastering two parts: the syntax and the patterns-of-use. This applies to human and computer-programming languages. These notes really only address the syntax part, but might make it possible to read Scala code sufficiently to get a general idea of what it is doing. Maybe.

The home page for the Scala programming language contains an excellent introduction from which some of these notes come. I can also recommend the book “Programming Scala Second Edition”. The wikipedia page on scala also provides a good overview for Java developers.

Scala is a big complicated language, with both OO and Functional options; this is the price paid for having an “easy upgrade path” from Java, and the ability to use existing Java libraries. Having two choices makes writing code easier - the progrmmer can choose whichever style they are most familiar with. But it makes reading code harder - you need to know both styles in order to understand existing programs. I think this language with a small experienced team may be good, and with inexperienced programmers it would be hell. The scala video course I watched did have some useful tips for starting with scala; in particular the presenter recommended aiming for “functional in the small, OO in the large”. In other words, developers familiar with OO languages should not try to take on the most advanced “philosophies” of Scala immediately (eg the Scalaz library), but instead use the OO features of Scala at the component-level. At the class or method level, it is however useful to make use of immutable structures, lambdas, etc.

Guidelines for functional vs object styles: program in the small with functional, program in the large with OO. The concept of interfaces works really well for decoupling code. However mutability and a multiplicity of classes can lead to bugs and overcomplex/verbose code at lower levels - where the functional approach shines. OO programs are also a good fit for GUI frameworks.

Why Use Scala?

There are a whole bunch of things which just replace verbose Java usage with more compact code, and remove annoying Java limitations:

  • Gets rid of constructor code which just copies params to fields.
  • Automatically generates field accessors (getters/setters) where relevant
  • Fields of an object are accessed in sourcecode like java direct read/write but is compiled to a call to a getter/setter (and can be overridden in the called code if desired)
  • Has type inference, to get rid of complicated type-declarations for variables/fields.
  • Semicolons usually optional (except in complicated cases)
  • Return keyword optional in most cases
  • Can omit braces around body of single-line methods (see example below)
  • Supports operator overloading (eg defining a method named “+” for a custom class)
  • Keyword “new” often not needed (technically, not a language feature but companion objects typically provide factory methods)
  • Operator “==” is equivalent to “.equals” ie usually does value-comparison, not identity comparison. Identity comparison is available as “obj1.eq(obj2)”.
  • Any method can be invoked with “named parameters”, ie params can be passed in any order. Example: swap(op2=12, op1=17)
  • Methods can have default-values for parameters.
  • If-statements are expressions which return a value, eg “val x = if (expr) 1 else 2”
  • Import statements can define an alias-name for the imported type(s).
  • Local aliases can be defined for complicated type-definitions

The standard library provides a lot of functional-programming-style features if you wish to go that way. In particular, the immutable collection types make scalable multi-threaded applications easier to develop.

Using Scala “opens a window” into the functional programming world while being more accessible than simply jumping into Haskell or similar, eg:

  • Pattern Matching (deconstruction-based switches)
  • Currying
  • Tuples
  • Explicit Tail Call Optimisation

And there are many external libraries for Scala which provide interesting functionality in functional-programming-style, including Akka and Play.

The primary disadvantages of Scala are:

  • much slower compilation times
  • poorer binary compatibility (often code compiled with Scala is only compatible with code compiled with exactly the same release of Scala)
  • calling Java code can be clumsy
  • not as widely known as Java (ie finding other developers and advice is more challenging)

The Scala Implementation

The Scala compiler, libraries, and tools are licensed under a “bsd-like” license; the code can be downloaded from an SVN repo. Development appears to happen on open lists, which is good.

The Scala Environment

Scala 2.12.0 and later runs on any JVM v1.8 or later (ie Scala code compiles to Java bytecode); earlier versions of Scala required only Java 1.6. Scala code can call Java libraries (though sometimes some workarounds are needed, eg converting a scala collection-type into its java.util.* equivalent before passing it as a parameter to a java method).

The standard Scala distribution previously had support for compiling Scala code to the CLR environment, ie Microsoft .Net runtime. However this support was removed in Scala v2.11 (2014).

There are good Scala plugins for Eclipse, Intellij and NetBeans IDEs.

Scala applications can be built with standard Java build-tools (eg Maven) or with the Scala-specific SBT (Scala Build Tool).

As with many languages, the standard Scala toolset provides a REPL (Read Eval Print Loop) tool, with which Scala code can be experimented with. Fragments of code can be entered and immediately executed. Methods defined via the REPL are added to a special “global class”.

Basic Application Structure

Scala code ist stored in plain text files, using UTF8 encoding. The standard file suffix is “.scala”. However Scala does not follow Java’s one-file-per-class approach; a single file can contain multiple definitions.

The primary “structural” components are packages, classes, traits and objects.

Packages are similar to those in Java. However:

  • Scala code often names packages following conventions common in languages like C++, Python or Ruby rather than Java’s widely-spread “reverse domain name” structure.
  • Package naming hierarchies are often “shallower” than in Java.
  • Package names can contain dots, eg “package foo.bar” declares a single package with name “foo.bar”, not a nested package “bar” with a parent package “foo”.

Classes are roughly similar to classes in Java. The “case class” is a variant of class that acts more like a “struct” or DTO (Data Transfer Object).

Traits are roughly similar to interfaces in Java.

Objects are somewhat like “singleton instances” in Java, ie are like declaring a class and applying the static singleton design pattern. An object-declaration in the same file as a class-declaration and using the same name as the class is called a “companion object” for the class and has access to the private members and methods of that class.

Basic Code Syntax

Source code blocks are delimited by braces, as with Java (not indentation-based as with Python). However semicolons are optional in most cases, and the conventional style is to omit them except in the rare situations where they really are required.

By convention, types start with upper-case letters while variables start with lower-case letters, as in Java.

Packages, classes and traits (like interfaces) are declared reasonably similarly to Java. Singleton types can also be declared in a manner similar to classes, using the “object” keyword.

Methods are declared using “def”. When an “=” follows the declaration, then this is a concrete method; when it is not present then the method is abstract.

Variables are declared using either “val” (immutable; roughly equivalent to java final) or “var” (mutable).

Type inference may be used in variable and member declarations, ie declarations do not include an explicit type - the compiler figures it out from the context. Method return types may also be omitted when they can be inferred by the compiler. However method parameter types must always be explicitly defined. This is not a radical change in the language, just a nice way to reduce clutter. Note that Java has a little bit of type inference itself : the “<>” syntax.

When types are present, they usually follow the name of some element rather than precede it, eg “var foo : String” rather than Java’s “String foo;”.

Generics in Scala is a bit different than Java, but roughly “[T]” means “<T>”.

Java’s primitive types are replaced by Scala “value types” which are accessed like objects, but can potentially be as efficient as the Java primitive equivalents. These types are named Byte, Int, Long, etc.

Arrays in Scala do not use square-brackets for declaration or indexing. Arrays are real objects with methods, and creating an array and reading/writing its elements is done via methods not special-case syntax as in Java. Reading/writing is actually done via a special “apply” method which can be invoked without the method-name; thus copying an element from one array to another looks like “dest(i) = src(j)”.

Scala allows nested function definitions.

Scala code can include inline xml (no escaping required).

Scala has no static fields or methods. The primary purpose of Java static fields and methods is to provide a single instance of a variable or constant, or a single implementation of a method. Scala singleton objects are “types with a single instance”, so provide a suitable home for such fields and methods.

Scala has no checked exceptions - only unchecked ones. Otherwise, exceptions work similarly to Java, with throw and catch keywords. Exceptions are used slightly less often in Scala than Java, given standard-library types such as Option and Either which make it easier to return error-indicating objects on failure.

The Scala Type Hierarchy, Value Types and Java Primitive Types

Every type in Scala is a subytpe of scala.Any. This has two subtypes:

  • scala.AnyVal is the parent of all “value types”
  • scala.AnyRef is the parent of all “reference types”

Value-types are the kinds of things allocated “on the stack” or embedded inline into other objects, and so garbage collection is not relevant for them. They have no identity, only a value. Equality comparisons therefore always are value-comparisons, and never identity-comparisons. Specifically, methods on the type-definition are not permitted to do anything that would require a “new” operation (ie heap allocation) at runtime. This ensures the methods can be compiled down to a set of helper functions rather than requiring real objects. The result is code that looks object-oriented but which is as efficient as procedural code. The scala wrappers for the primitive java types (int, double, char, etc) are all of this kind (called “value classes”), removing the clumsy Java distinction between primitives and objects without performance hit. It is also allowed (and useful) for users to define their own “value classes” as no-overhead wrappers for their own datatypes.

Reference-types are the kinds of things allocated “on the heap”. Local stack-frames and other objects may hold references (pointers) to them, but they are not “embedded” into other objects, and may be garbage-collected if no references to them remain.

Just about every type in Scala subclasses scala.AnyRef, and act much like Java classes.

The kinds of methods found on java.lang.Object (ie those common to every object instance) are spread between Any and AnyRef.

TODO: What about List[Int]? How does that fit with “value types”?

Type “Unit” is the equivalent of Java “void”, and the single value of this type is written “()”. The keyword “null” is also used.

Typecasts are done via a method defined on a base Scala type (ie available on any object):

  var x = myref.asInstanceof[Int]

Alternative names (“type aliases”) can be defined for existing types, just for convenience:

type Foo = Bar   # defines a "type alias"

Variables

Vals and Vars

Scala provides keyword “val” to declare references that cannot change. But the object pointed to can still change - unless it is an immutable type. It might be nice to have the equivalent of c++ “const”. Or at least some way of declaring that a class is immutable, which the compiler would check.

A class can be annotated as immutable; it is then a compile-error if any member is “var”, or if the type of any member is a mutable type.

When a parent class is immutable, then it is a runtime error if a subclass is mutable; this needs classloader support.

Interesting: can you subclass “List” to create a mutable type that is assignable to List?

Variable Declaration Syntax

Scala puts the variable-name before the type, eg

  val foo : Int = 3
  var bar : String = "hello" // initialized but mutable
  var baz : String // uninitialized

instead of

  final int foo = 3;
  String bar = "hello"; // initialized but mutable
  String baz;  // uninitialized

Type inference often allows the explicit type declaraton to be omitted:

  val pi = 3.14     // implicitly Double
  val foo = 3       // implicitly Int
  var bar = "hello" // implicitly String
  var baz : String

The Scala var/type ordering works better with type inference. I rather like it, as it mimics natural language better: “foo is an integer”.

A val declaration must be initialised, like final variables in Java. Obviously it makes no sense to have an uninitialised immutable reference.

A val or var declaration can be initialised to reference a lambda aka an anonymous function:

  val myfunc = {.....}

A string written as s"..." is an interpolated-string; any “${}” text in the string will be expanded.

Instances of classes are created with “new” (as in Java). However it is very common to define a factory method on a “companion object”; this is described in more detail later but means that calls to new are less commonly seen when reading Scala code. As an example: val mylist = List(1,2,3) is using the “default apply method” on the List companion object to instantiate a new list, ie that method acts as a factory.

Almost Everything is an Expression

Almost every code-structure that can be used within a method returns a value. In Java, things like if/for/while/switch are statements without return-value, but in Scala each produces a result which can be used (eg assigned to a variable).

The fact that “if” returns a value is great:

  val x = if (a>0) a else b;

Methods

Basic Method Declarations

Methods declarations are permitted within class, trait and object declarations.

Methods are declared like:

   def helloTo(who: String):String = {return "Hello, " + who}

This syntax mimics natural language nicer than Java: “mymethod returns String”, and puts the important fact (function name) earlier than the subordinate fact (returns String).

Often the method return type can be deduced (see “type inference” above), in which case the explicit return-type declaration can be omitted:

   def helloTo(who:String) = {return "Hello, " + who}

   // Inferred return type is Int...
   def min(op1: Int, op2: Int) = {
     if (op1 <= op2)
       return op1 // Int returned
     else
       return op2 // Int returned
   }

By default, the return-value of any method is the result of the last expression evaluated in that method, ie the “return” keyword is often unnecessary:

   def helloTo(who:String) = {"Hello, " + who}

   def min(op1: Int, op2: Int) = {
     // an "if/else" is actually an expression which evaluates to one of its branches..
     if (op1 <= op2)
       op1
     else
       op2
   }

And when the method body is just one line, the braces can be omitted:

   def somemethod(x:Int, y:Int) = "Hello, World"
   def min(op1: Int, op2: Int) = if (op1 <= op2) op1 else op2

A method with no parameters may be defined without parentheses, in which case it must be invoked without parentheses. When defined with parentheses it may be invoked with or without them (inconsistency due to compatibility with Java). Convention: only “getter” methods without side-effects are written without parentheses. Example:

  def age = { currentYear - this.yearOfBirth }

An abstract method declaration is just as above, but without the “=” sign. In an abstract method declaration, the return-type must always be explicitly declared (obviously, it cannot be deduced from the method body as there is none).

Forgetting the equals is a common mistake for Java developers; unfortunately:

  • if the method declaration includes an explicit return-type then the Scala compiler sees an abstract method declaration whose return-type is being defined as an inline subclass (the “method body is seen as subtyping the previous type-name). Inline subclasses are not allowed in declarations, so this is an error - but currently a rather confusing one.

  • if the method declaration has no explicit return-type then the Scala compiler sees an abstract method with no return-type followed by an unrelated code-block. As abstract methods are required to have a return-type, this is also an error - but again a rather confusing one.

Implicit/Explicit Typing

The fact that type decls inside a function are inferred, but that functions must give explicit param types seems a good compromise. It removes pointless text while keeping confusion manageable.

Having strict typing is great for refactoring and understanding existing code - mandatory for large projects.

More on Method Declarations

Method-names can use, or be exclusively formed from, punctuation chars. Such methods can be overridden in subclasses just like any other method. Example:

   def <<(x:Int) = {...}

Such method names are not limited to a predefined set of operators - sequences of punctuation chars may be used as a method-name. These methods are usually called “operators”, even if they don’t mirror traditional operator-names such as “+” or “<<”. Just about any character can be used in a function or variable name, except quote/apostrophe/backtick/comma/semicolon/dot and those that come in pairs, ie “()[]{}”. Even reserved-words can be used as function or variable names as long as they are surrounded with backticks. A name which begins with an “operator character” must contain only operator characters.

Methods with variable numbers of parameters are supported as with Java, but with a different syntax:

  def add(operands: Int*) = ...

Methods are by default public within their owning class.

Method params can be given default values:

  def foo(reqdParam: String, optParam: String = "") = ...

Method Invocation - Named Parameters

Methods can be invoked using “named parameters”; given a standard method-declaration like:

  def swap(op1: Int, op2: Int)

it can be invoked as

  swap(op2=17, op1=12)

Method Invocation - Infix Form

The dot can be omitted when calling a method on an object. And you can omit parentheses when invoking any method with one parameter. So instead of this:

  foo.bar(12)
  fix.fox(13,14)

you can write this:

  foo bar 12
  fix fox(13,14)

This is particularly useful when overriding operators:

  foo.+(13)   // invoke the method named "+" on object foo
  foo + 13    // same as above

Combining this with the ability to define method-names consisting of punctuation characters can lead to elegant-looking APIs, or simply unreadable ones. The widely-used Akka library uses this to allow code like “sender ! Response(errMsg)” - meaning invoke the method named “!” on object “sender” passing the return value of (special) method Response.apply(errMsg) method as a parameter.

Interestingly, the source-code for standard class “scala.Int” includes this declaration:

   def +(x:Int): Int

which is what allows us to write

  val sum = 1 + 4

Operator Precedence

When invoking a series of methods using infix form, the question of precedence arises, eg:

  val x1 = 1 + 3 * 8                        // traditional example
  val x2 = foo +- bar *^ baz                // some infix methods with non-ascii names
  val x3 = foo plusminus bar starcarat baz  // some infix methods with ascii names

Mathematical operators have well-known precedence: multiplication has higher precendence than addition, so the first example is interpreted as 1 + (3 * 8).

In Scala, there is a standard set of operator-characters which have a fixed precedence (eg +-); the programmer cannot override these precedences. A method-name which starts with such a character has the fixed precedence value of that character, ie a method’s precedence is set by the first character of its name. While this is a loss of flexibility, making precedence dynamic (ie allowing functions to declare operator precedence) would probably lead to totally unreadable code.

Method names used in infix-form which do not start with a recognised operator-character all have the same precedence.

The first two of the above examples are therefore equivalent to:

  val x1 = 1 + (3 * 8)
  val x2 = foo.+-(bar.*^(baz))

In the third example, methods “plusminus” and “starcarat” have the same precedence, so the question of associativity arises - see below.

Operator Associativity

When invoking a series of methods using infix form, and the methods have the same precedence, then the question of associativity arises, eg:

  val x1 = 1 + 3 + 5                        // traditional example
  val x2 = foo +- bar +- baz                // some infix methods with non-ascii names
  val x3 = foo plusminus bar starcarat baz  // some infix methods with ascii names

Mathematical operators have well-known associations: they almost all associate left-to-right, so the first example is interpreted as (1+3)+5.

In Scala, each standard operator-character has a fixed associativity; the programmer cannot override it. When used in infix-form, a method’s associativity is set by the last character of its name. Methods used in infix-form which do not end with a recognised operator-character all have left-to-right associativity.

The above examples are therefore equivalent to:

  val x1 = (1 + 3) + 8
  val x2 = (foo.+-(bar)).+-(baz)
  val x3 = (foo.plusminus(bar)).starcarat(baz)

One particularly important operator in Scala is :: which means “concatenation”. The standard linked-list type provides a method with this name for building lists, and if you are familiar with functional programming you will know how often linked lists are used. Interestingly, :: is right-associative (ie different from most other operators). Actually, what is done in Scala is to define character : as right-associative, meaning any method ending in a colon (including ::) is right-associative.

Thus:

   val l1 = 1 :: 2 :: Nil;  // creates (1,2)
   val l1a = 0 :: l1;       // creates (0,1,2)
   val l2 = 3 :: 4:: Nil;   // creates (3,4)
   val all = l1 ::: l2;     // triple-colon is "flattening concatenation" which creates (1,2,3,4)

Operator Binding

Above, it was mentioned that “a op b” is equivalent to “a.op(b)”. There is one exception in Scala - for any method-name ending with a colon, “a op b” is instead equivalent to “b.op(a)”. In particular, lists are commonly built like “1 :: 2 :: Nil” which is equivalent to “List.Nil.::(2).::(1)”.

Point-free Style

Taken to extreme, this ability to use “infix” form for methods taking one parameter leads to something called “point free style”. For example:

  List(1,2,3,4) filter isEven foreach println

is equivalent to

  val input = List(1,2,3,4)
  input.filter(isEven).foreach(println)

In the above code, type List has a method filter which returns an object of type Seq which has a method foreach which takes a function-reference.

Tuples

A tuple is somewhere between an array and a datastructure. Like an array, it is a fixed-size sequence of references to other objects. Unlike an array, each reference can have a different type. Tuples are defined simply like ("hello", 123, 12.45, "world"). The values in a tuple are usually accessed via pattern matching (see later).

Classes

Basic Class Declarations

A Scala “class” declaration is roughly like a Java class declaration. However the class can have only one constructor, and that constructor is kind of squashed into the class declaration header:

  class User(val id: Int, var name: String, comment: String = "no comment") {
    var isActive = false
    private var foo = "something"

    def printme() = println(name + ":" + comment)
  }

The “class parameters” are simultaneously constructor-parameters and members of the class; the members are automatically initialized to whatever the caller provided (saving the often boring boilerplate found in many Java class constructors). There is no way to “intercept” and modify the input parameters from within the class, as often done in Java constructors; instead a factory-method can be used to ensure the correct params are passed.

The modifier on class-parameter id is “val”, so this becomes an immutable member with a public getter. The modifier on “name” is var, so this becomes a mutable member with auto-generated public getter and setter. There is no modifier on comment, so this effectively becomes a private val member. Class-parameters can be explicitly declared “private var” or “private val” if desired.

As with method parameters, constructor-parameters can have default values.

The scala compiler generates regular Java “.class” files as output, and running a Java decompiler on the classfile will show that Scala generates a Java class for each Scala class. The class has a constructor matching the parameters in the Scala class-definition, and getters/setters for those params and members declared with val/var.

Overriding the getter or setter for a member is not directly possible. Instead, you define the member as private, then define a read and/or write method which returns the private value:

  class Foo {
    private var idInternal : Int = null   // Choose a name that does not conflict with the desired public API. Often a leading underscore is used for this purpose..

    // Getter method usable like "var x = foo.id". Note that the method is declared with _no parameters_ (not even an empty-list).
    def id = {
      println("Getting id")
      idInternal
    }

    // Setter method callable like "foo.id = 12"
    def id_=(value: Int) = {
      println("Setting id")
      idInternal = value;
    }
  }

If defining a setter in this way, it is mandatory to also explicitly define a getter.

A member which is declared without an initial value is “abstract” (obvious for immutables vals; not so obvious for vars). Null may be used as an initialization value.

There are three special method-names that can be defined on a class: apply, unapply and update. See “special methods” later.

There are also some special “modifiers” which can be applied to a method-declaration: the familiar “public” or “protected”, and the scala-specific “implicit” (see later). The Java modifier “abstract” is not needed in Scala; any method without a body is abstract, and any class with an abstract method is abstract.

Traits (interfaces) and inheritance are discussed later.

More on Class Constructors

Here is an example of a class with some constructor-parameters and constructor logic:

  class User(val id: Int, var name: String, comment: String) {
    println("Primary constructor: running..")

    println("Primary constructor: Initialising internal var isActive")
    var isActive = false

    println("Primary constructor: Initialising internal var foo")
    private var foo = "something"

    // secondary (alternate) constructor
    def this(id: Int) {
      // delegate to the primary constructor above
      this(id, "unknown", "no comment")
    }

    def printme() = println(name + ":" + comment)

    println("Primary constructor: still running...")
  }

Note that the codeblock after the “class .. “ declaration is actually a kind of method-body, containing code. However variables declared in this method-body are also members of the class, and continue to exist after the constructor completes. This will feel somewhat familiar to Javascript developers, where a “constructor” actually creates variables and defines methods by storing data in the associated map. Scala is of course more statically-typed, but there are some similarities.

The above demonstrates a secondary constructor, which is declared as a method with name “this”. Note that there is no “=” between declaration and implementation. The implementation must itself call “this” to delegate to another constructor (eg the primary). Of course this particular secondary constructor, which just sets default values for parameters, can instead be implemented by defining default values directly in the primary constructor params..

The primary constructor may be made private via

  class User private (....) {..}

in which case instances can only be created via secondary constructors, or via factory-methods on a companion object (see later).

Case Classes

Scala has “case classes”, which are effectively a tuple with named elements. They are simple “data representation objects” or “data transfer objects” used for holding a bunch of related data.

A case-class instance is immutable, ie all its members are read-only. It cannot be subclassed (is “final” in Java terms).

It automatically has a public field for each constructor param, as usual for Scala classes - but “private” fields are not supported. Standard functions equals and toString are auto-generated, as is a “copy” method (which supports named params to change just specific fields), and an “unapply” method for use with pattern-matching. This all saves a lot of boilerplate code!

A case-class can extend existing classes as long as they have no abstract methods. Constructor params for the parent type(s) are passed along from the case-class constructor as usual in inheritance (see later).

You can define methods on a case-class, and can also define them on the companion object.

Creating an instance of a case-class can be done with the “new” keyword, but is usually done via a factory method on the companion object (which is auto-generated if not defined by the developer); see below.

Object Declarations (Singletons and Companion Objects)

A Scala “object” declaration defines a type of which there will be only one instance at runtime. On application startup, the object is automatically created; it is not possible to create more instances. The instance can be referenced via its “object name”.

  object MySingleton {
    val PI = 3.14       // declare members as usual
    def foo(...) = ...  // declare methods as usual
  }

  // Call it using its "object name" as the "instance"
  MySingleton.foo()

Such singleton objects can be used to do the kind of things which Java developers implement as static variables and static methods. It also replaces all use of the (old-fashioned) static-singleton-pattern from Java.

Singleton objects can extend a base class; they have a proper type after all (unlike Java statics).

The “main” method of an application (which is static in Java) is defined on a Scala singleton object as a method named “main(args: Array[String]”.

When an object-declaration has the same name as a Class definition, and is in the same file, then it is called a “companion object” to the class and its methods may also be applied by the compiler when user sourcecode performs specific operations on instances of the associated class; in particular it can define custom type-casting logic for that type.

A Scala class may call private methods of its companion object, and a companion object may call private methods on its companion class (including private constructors). Because of this, a companion object is commonly used to define factory methods for the type with the same name:

  // class with no public constructor
  class User private (val id: Int, var name: String, comment: String) {...}

  // companion object
  object User {

    // trivial factory method
    def create(id: Int, name: String, comment: String) = new User(id, name, comment)
  }

  // Use the factory-method
  var user1 = User.create(1, "fred", "no comment")

If you use a Java decompiler on the generated code for a class with a “companion object”, you will see that the class has a method which returns the associated “companion object” instance, rather in the way the static-singleton-pattern is traditionally implemented in Java.

A method named “apply” on a class or object acts as a “default method” which can be invoked without specifying its name. If a class named Foo has a method named apply, then it can be invoked on an instance of Foo like someFoo.apply(12) or simply someFoo(12). As seen in the first example above, methods on an object-declaration SomeObject are invoked as SomeObject.method(..); thus an apply-method can be invoked simply as SomeObject(...). This makes the apply method a nice way to provide factory methods for the class of the same name:

  // class with no public constructor
  class User private (val id: Int, var name: String, comment: String) {...}

  // companion object
  object User {
    def apply(id: Int, name: String, comment: String) = new User(id, name, comment)
  }

  // Use the factory-method: invokes singleton-object-method User.apply(...)
  var user1 = User(1, "fred", "no comment")

This factory-pattern (companion + apply-method) can be found often in Scala, eg the standard List type: “val mylist = List(....)” invokes List.apply(...) on “object List”.

Scala object-types should not be overused. Statics are a pain when testing in Java; it is far nicer when a class under test has a “provider object” injected into it during construction. In production Java code, the object injected can be a singleton while in testing it can be a mock. The same approach should be taken in Scala, ie if you may need to mock instances for testing then don’t make them singleton “objects”.

Traits (interfaces)

Scala’s equivalent of Java interfaces is the trait. It works similarly to interfaces, and is pretty obvious.

A trait is meant to be used to define behaviour that is relevant to many different unrelated types, eg “serializable” could be a good trait, or “closeable”:

  trait Closeable {
    def close(): Unit
  }

Traits may (obviously) have abstract method definitions. Like class-based abstract methods, the return-type must be explicitly defined.

Like Java8 interfaces, traits may also have concrete method definitions - methods with bodies.

Unlike interfaces, traits can also declare members.

  • When the member is abstract (not initialised with a value) then any class which implements that trait must itself declare a member with that name. A similar effect can be obtained in Java by having the interface define abstract getter/setter methods and then use these in a concrete method implementation.

  • When the trait member is initialised then all classes which inherit from the trait automatically get a member of that name. This isn’t quite the same as inheriting a member from an ancestor class, ie this isn’t full “multiple inheritance”. Apparently, Scala somehow works around the complexities needed to implement multiple inheritance in languages such as C++, though it isn’t clear to me how that occurs. See the Scala documentation for the complete details.

Traits do not have constructors.

Traits which declare members (whether abstract or not) are often refered to as mixins.

Inheritance

Scala inheritance works reasonably similarly to Java, but the syntax is a little different:

    class Derived (val arg1: Int, arg2: String)
      extends Base(arg2) with Closeable with Serializable {
      ...
    }

At most one base class may be specified, but multiple traits are permitted. The first ancestor type is indicated using “extends” and subsequent ones are indicated using “with”.

Any parameters required by the base-class must simply be mapped 1:1 from constructor-params of the subclass. Neither “val” nor “var” can be specified on arguments being forwarded to the base-class, as the primary-constructor params declared on the base-class are members which the derived class then inherits.

Traits do not have constructors, so a class never needs to pass arguments to a trait it implements.

A problem with multiple-inheritance of traits or interfaces is what to do when the same method (or field in the case of traits) is defined in multiple ancestor types. In Scala, the order in which traits are listed in the “with” clause is significant in resolving these conflicts (aka “Linearization”). Java8 simply reports a compiler-error in this case.

A trait may extend a class as well as another trait. In this case, the trait may use “super” in its method-definitions to call methods on the base class. When a concrete class mixes in multiple traits which extend the same base type and override the same method, then overridden methods in traits are invoked somewhat like a chain of superclasses - in the order in which the concrete class declares the mixins.

When a subclass reimplements a concrete method defined in an ancestor type, the Scala keyword “override” must be added to the “def” statement (similar to Java’s @Override annotation, but mandatory). As in Java, keyword “super” is used to invoke methods in the base class.

When a class does not declare an ancestor type then its default ancestor type is standard type AnyRef (similar to Java’s Object type).

Guidelines for subclassing:

  • never derive an abstract class from another abstract class
  • never derive a concrete class from a concrete class except to add mixins (pure logic without fields)
  • when a problem seems to require one of the above, try to use the adapter pattern.

My suggestion: a type should protect its invariants, but significant logic should be external - particularly logic that involves multiple types or references to services.

Anonymous Subclasses

The syntax “new Foo with Bar” creates a new instance of an anonymous class which is a subclass of Foo and implements Bar. Any custom code in the new anonymous class can reference methods defined in the “with” mixin. All code in the same scope also sees the variable as the anonymous subtype, ie can call the mixin methods. Obviously if the instance is passed into some other function or returned then it is only accessable as the specified param-type or return-type.

Implicit Methods, Type Conversion and Type Classes

When a method M is invoked on a type T which does not have any such method, the compiler searches for a function in scope which is marked “implicit”, takes one parameter matching type T, and returns a type Q which does have the required method M. This is called an “implicit conversion”. To shorten the code, it is also possible to mark type Q as implicit directly (the constructor for Q must take one param of type T). This feature should not be overused, and the code must deliberately enable this feature via “import scala.language.implicitConversions”.

Interestingly, this effectively allows “adapters” to be defined for a type transparently, which is basically equivalent to adding methods to a type without modifying the definition of that type. This is similar to a Haskell “type class” or C# “extension methods”. Given some interface (trait), an implicit class can be defined that takes an instance of some type T and returns an adapter which implements that trait for that type.

One limitation is that this does not work well for objects being passed around as some abstract type. The lookup of the implicit conversion method/class is done on the declared type of the variable, not its runtime type.

These implicit conversions are used to handle mixed-type arithmetic, eg adding ints and longs. In most cases, the implicit-method-invocations are inlined in the generated code.

The standard-library type Option can be implicitly converted to a list of 0 or 1 items; this allows using an Option in a list-comprehension.

Some plain Java types (eg String) have implicit conversions to Scala wrappers which provide additional related methods. The primitive Java types have implicit conversions to “objectify” them. Java collection types have implicit converters which add methods like “asScala*” - ie these types are not directly converted to a Scala collection, but instead converted to an intermediate form that provides the option to elegantly but explicitly convert to the Scala equivalent.

Packages and Import Statements

Scala code is grouped into packages as with Java; a Scala sourcefile should start with a package-declaration like:

  package foo

All declarations following that line is within package foo. There is no absolute requirement on the directory-name in which the file is stored (scala tools can work with any desired structure). However some tools do assume that scala code in package X is in a directory with the same name, so that layout is still recommended.

Scala code often does not follow the java package-naming convention of “reverse internet domain names” (eg com.example.projectname.componentname); instead much “flatter” structures are often used. The scala standard libraries are usually just under package “scala”.

Nested packages are not defined with

   package foo.bar   // defines one package with name "foo.bar"

but with

   package foo
   package bar // nested inside foo

Unlike java, there is no mandatory link between package-name (as declared in the source-code) and the filename. A single file can declare multiple packages.

Imports work as in Java, ie just provide a short alias for the full name of something. However there are a few special things about imports in Scala, including the implicit qualifier on functions and classes (which are ignored unless imported) and language-features (see below).

As in java, a specific type can be imported. Unlike java, a function can be imported.

Wildcard imports use the “_” character rather than “*” (because “*” is a valid function-name in Scala, and an import-statement can specify the name of a function to import). A single “_” is a reserved word and thus not a valid function-name.

The import statement is also used to enable certain Scala language features; an import starting with “scala.language.” is not a real package but rather an indication that the specified feature should be enabled for the following code.

The import-statement can define a local “alias” for an imported type to avoid name clashes.

Generics

Generic Types

Scala has generics somewhat similar to Java, though more powerful and with a different syntax. Type-params are specified in square brackets (“[]”).

To declare an instance of a generic type:

  val myStrings = new List[String]

To declare a parameter of a generic type:

  def printAll(items: List[String]) = ...

Covariance, Contravariance and Type Bounds

The tricky java-generics “covariants” and “contravariants” support (“<T extends P>” and “<T super P>”) is replaced by expressions like:

  class Stack[+A] {
    def push[B >: A](b: B): Stack[B] = ...
  }

More obvious? No, not obviously. However it is more powerful. The above declarations mean that given a stack which holds objects of type A or its subtypes, method push takes a parameter which must be a subtype of A.

The equivalent of the Java generic “?” is Scala’s “Any” type. All scala types are subtypes of Any (including Int, Boolean, etc). The wildcard “_” can also be used.

  • A<:B” is an “upper type bound” (A must be an ancestor of B). This is equivalent to Java “<? extends B>”. Defines “out” types, useful to constrain types returned from methods.

  • Syntax “B>:A” is a “lower type bound” (B must extend A). This is equivalent to Java “<? super B>”. Defines “in” types, useful to specify types passed to methods.

  • List[_]” is equivalent to Java “List<?>

Abstract Type Declarations

An alternative way to express generic type parameters is to

An abstract class can include definition “type T” which is equivalent to java generic syntax “<T>”. Some subclass then declares “type T = sometype” to complete the definition. As example:

  class MyGenericClass {
    abstract type Foo
    abstract Foo templateFn()
  }

Variance

Given that B is a subtype of A, what is the relationship between List<A> and List<B>?

  • invariant: no relation, incompatible
  • covariant: List<B> can be cast to List<A>, ie someListOfA = someListOfB
  • contravariant: List<A> can be cast to List<B>, ie someListOfB = someListOfA.

In general, covariance is useful when reading values of the generic type, while contravariance is useful when writing values of the generic type.

Java classes are always invariant, except in two special cases: arrays and method-return-types.

An example of Java array covariance:

// Create a "view" of the underlying string array as a different type
Object[] objarray = new String[]{"s1", "s2"};

// Same principle as above, this time with a parameter instead of a variable
void methodTakingArray(Object[] data) {...}
methodTakingArray(new String[]{"p1", "p2"});

// Negative side of array covariance: covariance is good for _reading_ but bad for _writing_..
objarray[0] = Boolean.TRUE; // this write-operation compiles but throws exception at runtime!

And in Java, given a parent type defining a method returning A, a subtype can override the method and return a subtype of A.

Scala has very sophisticated facilities for expressing generic variance constraints, including:

  • List[+A] (covariance)
  • List[-A] (contravariance)

Generic Self Types

A trait can declare “this: sometype =>” which requires that any type extending that trait must be a subtype of sometype. Method implementations on the trait can then access methods defined on the specified type-bound. Example uses are traits which can only be used together with types that are “serializable” (have a write method) or “ordered” (have a compare method).

Pattern Matching

Patttern-matching is like a “super switch statement”:

  val result = somevar match {
     case expr1|expr2 => val1
     case expr3 => val2
     case _ => defaultval
  }

Pattern-matching can be applied to lists and tuples. Any other type can make itself pattern-matchable by defining an “unapply” method which generates a tuple representing the object’s matchable state; this method is often defined on the “companion object” for a type.

An “object” declaration can be used as a helper in pattern-matching deconstruction. A statement of form “x match { case Foo(p1,p2) ..}” where Foo is an “object declaration” will call “Foo.unapply(x):Option[sometuple]”. When “None” is returned, then the case is considered not to match, otherwise the values in the nested tuple are assigned to p1,p2,etc. Alternatively, the unapply function can return Option[T] for one value, or Boolean for no output params.

Unlike Java, scala types don’t have to be defined in a file of the same name. A “package” declaration can be used anywhere (and nested within a file). Typically a source-file holds more types than in Java.

There is an “instanceof” method defined on a base Scala type (and thus available on every object). However it is considered better style in Scala to use pattern-matching when the type is not known.

Also can be used as a replacement for “instanceof” type operations. A pattern which matches a specific type can extract fields of the instance in an elegant way. This can be customised for any class by defining a function with the magic name “unapply” which takes an instance of that type and returns a tuple; the fields of the tuple are what must match the expression in “case {expr}”. Unapply functions are usually implemented on the companion object for a class (which can access private fields of the associated class) but can be defined on an unrelated singleton-object if desired (eg the target class sourcecode is not modifiable).

The full details are too complex to be described here.

A class declared as “sealed” can only be subtyped in the same file. This allows the developer/compiler to know the full set of subtypes is fixed. This is particularly useful in pattern-matching statements where the compiler can determine whether a “default” clause is required or not.

Functions and Lambdas

Anonymous Function Declaration

Method declarations use the “def” keyword and are statements; they have a side-effect and return no result. They are also “compile-time-only” structures.

Function definitions instead return a result that must be stored in a variable or passed as a parameter. They are partly compile-time; the compiler checks the syntax and generates code for them. However because they “return a result”, they are also have runtime behaviour. Functions are also called anonymous functions, closures, or lambdas.

Function declaration syntax is similar to method-declaration syntax. However it:

  • does not use “def”
  • puts the args before a “=>” operator

The full syntax is:

   val f1 = (x:Int, y:Int):Int => {return 0}

Often the return type can be deduced:

   val f1 = (x:Int,y:Int) => {return 0}

The return-statement can usually be omitted. And when the body is just one line, the braces can be omitted:

   val f1 = (x:Int, y:Int) => 0

More examples of anonymous function definitions:

  var f1 = (x: Int) => x + 1
  var f2 = (x: Int, y:String) => {...}
  var f3 = () => println("Hello, World")

As with method declarations, braces are optional when the body only has one line, and the “return” keyword is optional (and usually omitted).

Because the “this” reference associated with a method defined on a Scala “singleton object” is always uniquely identifiable, methods on singleton objects can also be used as functions:

  var pln = scala.Predef.println

This is similar to the way Java can use static methods as lambdas via syntax like “System::println”. Methods of a singleton object can actually be imported via an import-statement, making them callable without needing the name of the singleton object type - and all methods of scala.Predef are imported by default, thus “println” can simply be written directly.

Lambdas are sometimes called functions or anonymous functions.

The (formal params) part can be left out; the code can then refer to the parameters using “_”, eg the following are equivalent:

  var f1a = (msg: String) => println(msg)
  var f1b = println(_)

  var f2a = (x:Int, y:Int) => x + y
  var f2b = (_ + _)  // Question: how are the types determined here?

  var f3a = list map { x => sqrt(x) }
  var f3b = list map { sqrt(_) }
  var f3c = list map sqrt

In f1b, the compiler detects when the right-hand-side of an expression contains an underscore, and realizes that this expression is not a simple method-call but instead an anonymous function definition. This allows the function to be defined without the leading (..) => syntax.

In f2b, there are two underscores, so the function assigned to f2b will have two parameters. The type of the arguments is ?? (try the REPL to find out..)

Anonymous functions “capture” referenced variables in their context, ie are closures.

I personally find the “_” syntax rather ugly - something like “$1” might have been nicer. However using underscores for param-placeholders has a long tradition in functional programming languages.

Declaring Methods Which Take a Function as Parameter

When defining a method which takes a function as a parameter, the syntax looks like:

   // first param is a function with one Int parameter and a String return value
   def high1(f: Int => String) : String = ....`

   // first param is a function with two Int parameters and a Double return value
   def high2(f: (Int, Int) => Double) : String = ....`

   // second param is a function with no parameters and a Long return value
   def high3(a: String,  f: () => Long) : () = ....`

Partial Function Application aka Currying

Scala has partial function application; calling a function with too few arguments returns reference-to-function rather than being a compile-error.

Method parameters can be declared as “SomeMethod(f:ftype,g:gtype)” or as “SomeMethod(f:ftype)(g:gtype)”. In the first case, it must be invoked as “SomeMethod(p1,p2)” while in the second case it must be invoked as “SomeMethod(p1)(p2)”. In the second case, when p2 is a functiontype then a function “{x => ..}” code-block can be passed.

Normally, any use of a variable which points to a function automatically triggers invocation of that function. To get a reference to a datastructure describing the function it is necessary to write “fref _” (somewhat like “&function” in C or Perl).

A function defined with a multi-value parameter list can be explicitly converted to curried-form via syntax “(fname _).curried”, after which it can be “partially applied” as desired. To “curry” a function means rewriting it as a chain of functions each of which take one parameter; all except the last have a return-value which is a function that takes one parameter and the last function triggers the actual work and has the “real” return type. The “builder pattern” is somewhat similar to a curried function; the user invokes a series of single-parameter “set” methods followed by a “build” method.

A nice syntactic sugar exists for defining functions that are likely to be partially-applied - the function prototype can have multiple parameter lists. When invoking the function, each individual parameter list must be fully-provided or omitted. However passing too-few parameter lists, followed by “_” results in a partially applied function. Only trailing parameter-lists can be omitted (ie only leading parameter-lists can be bound). I find the syntax somewhat weird.

The result is therefore not as flexible or consistent as (for example) Haskell, due to the fact that the function definition must be set up to support partial application, or the clumsy “.curried” method used, but it is possible.

When a parameter-list contains a single parameter of type nullary-function then the calling point can pass an expression (including a code-block). The code will be invoked each time the parameter is referenced, ie the parameter is a ref-to-function and the code-block at the call-site is automatically transformed to a function at compile-time.

A function defined with a single empty parameter-list can be invoked with or without parentheses. A function defined with zero parameter-lists can only be invoked without parentheses.

Passing a Code Block as a Function Parameter

When a function takes a single parameter which is a nullary function, then calling code (the point of invocation) passes a function, ie references to code rather than evaluating “the parameter value” before invocation. While this is technically limited to a single parameter, Scala allows a function prototype to have multiple parameter lists. Thus any number of functions can be passed, and these can be defined either as single expressions or as braced-compound-expressions:

A code-block in braces is a lambda with no params. Together with Scala’s ability to omit parentheses on method invocations with one parameter, it allows things like:

   execute {
      ...
   }

which calls method “execute(someClosure)” passing the codeblock as the function. This only works with a function of one parameter, but using currying allows this to be applied to any method whose last parameter is a function:

  def runme(arg0: String)(torun: => String) = {   // curryable method with more than one argument-lists
    var result = torun  // invoke function now
    println("runme:" + arg0 + ", " + result)
  }

  runme("hello") {
    "big" + " world"
  }

The following are equivalent:

val succ = (x:Int) => x + 1

val succFunction = new Function1[Int,Int] {
  def apply(x:Int) : Int = x + 1
}

# this creates a subclass of FunctionN which has an object-ref, and an apply method which delegates
# to the corresponding method of the class. It then creates an instance of that type with objref=someobj.
# Hmm..but what about overloaded methods?
val funcFromMethod = someObj.someMethod _

Dynamic Types

A class which “extends Dynamic” can be invoked with any method at all. When the compiler sees that source-code is invoking a method which is not defined at compile-time, and the target type implements Dynamic, then the compiler instead produces code that invokes a suitable generic method on the class; for example invoking a simple no-params “getter” such as obj.fieldname() triggers a call to “obj.selectDynamic(fieldname)”.

Custom Assignment Operators

Argument-list following an object is converted into an “apply” or “update” call:

  val i = a(2);   // a.apply(2)
  a(2) = 1;   // a.update(2, 1)

This is nice. Particularly nice is that plain names are used - “apply/update” rather than cryptic symbols. Ok, perhaps this is not so friendly for non-english speakers, but….

The “parentheses calls apply” also conflicts somewhat with the nice lisp convention of “parentheses build a list” which works really well. Instead, the convention could be that “parentheses build a list”, and object-followed-by-list-means-apply. This could solve the ugly “::” associativity problem for lists at least.

Having a trailing underscore on an operator overloading function to indicate “assign to” is really nasty…

–> todo: need example

Loops

There is a for-loop that is similar to Java, though the syntax is slightly different:

   for(item <- list) {
     ..
   }

However scala code more commonly uses this form instead:

  list.foreach(...)

Integers are objects, and have a method “to” which return a Range object, which is iterable. This allows things like:

  (0 to 100).foreach(....)

and

   for(i <- 0 to 9) ..

While and do-while loops are similar to Java.

For-loops are actually capable of more than just the above; they are actually a wrapper around map and flatmap methods. See later for information on “for-comprehensions”.

Standard Library

Arrays

Arrays use () for access. Yeah, ok. This is because square-brackets are used for generic-types:

  val foo : Array[String].

This array-access-looking-like-function is odd, but bearable.

But wouldn’t it have been better to use “<>” for type demarcation, as usual?

   val foo : Array<String>

This does have the old disadvantage for nested types:

   val foo : Array<<String,Int>, Int>

causes confusion with token “<<”. But as operators can be defined in scala, what stops someone defining “[[” as an operator and causing the same problem?

They argue that foo(2) is just foo.apply(2). But why not make [] and () the same? Then bar[2] means bar.apply(2) too. Ok, it is redundant, but makes code nice.

The whole concept of arrays is really rather crap. This “mutable” type doesn’t fit well with the functional world. There should possibly be an immutable array type too; a “list” is not the same thing.

Collections, Sequences and Lists

Scala provides a collections library which has a selection of both immutable and mutable types. The immutable ones should be used where possible. Java’s standard library is also available for communicating with Java code.

This library has helper methods for converting to and from Java’s collection types (for interacting with standard Java libraries). Collection types support typical functional operations such as foreach, map, flatmap:

   val mylist = List("a","b","c") // use factory method on List companion object to instantiate an immutable list
   mylist.foreach(value=>println(value)) // function aka lambda
   mylist.foreach(println) // method reference (identical behaviour to previous line)

The scala List type is a “strict” collection. Its transform methods (eg map, filter) immediately process the input list and produce another list.

Like lisp lists, it is possible to prepend to such a list efficiently, creating a new list that has new elements at the start then points to the original list as its tail. Syntax: “val foo = newelement :: origlist”, which invokes method “origlist.::”

Map functions:

  • scala has List.map(fn) and List.flatMap(fn)

The scala View and Stream collections are instead “on-demand” (pipeline or lazy) collections. Their transform methods (map,filter,etc) return closures which pull data from the original collection only as-needed (similar to Haskell). Method List.view produces a view over a list.

List efficiency

In order to support head/tail operations efficiently on lists, they really do need to be singly-linked-lists. It would be possible to have an array-type implementation plus offset. However freeing no-longer-needed head objects is then not possible.

Each list node is always of a fixed size (two pointers, being “item” and “nextnode”). Therefore managing reusable pools of these nodes is pretty easy; just allocate an array of 5000 of them at a time. And freed nodes can go back on the head of the list, so “cache hotness” will work well. Therefore the memory-management overhead is really not too bad - it is certainly not a generic malloc/free (or garbage-collection operation) for each discarded head node.

Note that although lists are immutable, the elements in the list may be mutable objects.

Special Methods

There are three special method-names in Scala: apply, unapply and update.

If a class defines a method named “apply”, then that method can be called without writing “.apply”. This can be considered “the default method” for the class:

   class User .. {
     def apply(prefix: String) {
     }
   }

   val user = new User()
   user.apply("hello, ")  // normal method invocation
   user("hello, ")  // same as above - but looks like a "function call" not a method-call.

There can be multiple apply methods with different parameter-lists.

The Array class uses this to implement its “get-item-at-index” operation (which is a normal method, not a special case as with Java):

   val items = new Array("first", "second")
   val item = items(1)  // actually calls Array.apply(Int)

The “update” method is invoked for assignment:

   class User .. {
     def update(index: Int, String value) = ...
   }

   val user = new User()
   user(2) = "foo"   // calls user.update(2, "foo")

Exceptions

No checked exceptions (all runtime exceptions). Otherwise, similar.

When calling Java libraries that throw checked exceptions, these are converted to runtime exceptions.

A try/catch block in Scala is almost identical to Java. Only difference is in the catch clause, which uses a match-expression:

   try {
     --
   } catch {
      case expr1: ...
   }

Map and Flatmap

The methods “map” and “flatmap” are used extremely often in Scala, and are available on many classes from the standard library. In short: given some object that holds one or more values (collection-types and things like Option), apply a transformation to the value(s). With method “map(somefn)”, the function must return exactly one output for each input value; the result of someobj.map(..) therefore wraps exactly as many values as someobj did. With “flatmap(somefn)”, the function may return zero or more outputs; the result of someobj.flatmap(…) therefore wraps an indeterminate number of values.

For-comprehensions

The “yield” call in a for-loop effectively converts a “for” into a “flatmap” call:

  for(i <- 0 to 5) yield i

is equivalent to

  (0.to(5)).flatmap(i=>i)

Annotations

Scala has annotations which resemble Java annotations. Some standard annotations include:

  • @transient, @volatile
  • @scala.beans.BeanProperty - can be added to any member of a class, and triggers generation of a getX method; mutable members also get a setX method.
  • @tailrec - requires the compiler to report an error if the annotated method cannot be compiled with “tail recursion optimisation”

Custom annotations are simply defined as traits which extend scala.Annotation or one of its subtypes.

Tail Recursion

Functional programming style uses recursive code definitions more often than traditional OO programming styles do. When a recursive function is implemented correctly, and the compiler implements “tail recursion optimisation” then recursive calls can compile to code just as efficient as an imperative loop. The Scala compiler does implement tail recursion optimisation.

Unfortunately, a slightly different recursive function may be impossible to apply “tail recursion optimisation” to; the code is then much less inefficient and potentially leads to stack-overflow errors. To catch such errors, a recursive function may be annotated with @tailrec; the compiler will then report an error if tail recursion optimisation is not possible.

Algebraic Data Types

An ADT is either a “product type” or “sum type”. Product types are familiar to OO developers - basically tuples and standard classes.

Sum types are roughly equivalent to a set of immutable classes implementing the same interface. In OO terminology, different types can be told apart at runtime via “is instance”. In non-OO functional languages, sum types are described as having a “type tag” - like a “tagged union” in C or Pascal.

Multithreading

Since v2.10, the Akka library is part of the Scala standard distribution, and provides an Actor-based library which also supports distributed processing.

The standard library also includes “parallel collections” - most standard types provide a “par” method which returns an object which offers map/flatmap methods which apply an anonymous function in parallel over the collection.

Other Minor Features

Scala supports “atoms” using form ‘someatom.

A parameter may be marked “lazy” in which case the expression used at the calling point is not evaluated until the parameter is first referenced. This effectively forces the actual parameter to be passed as an anonymous function (aka closure), rather than evaluating it at point-of-call.

Scala does not have any direct equivalent to Java enums.

Ecosystem

  • play, lift, scalatra, akka
  • scalaz (hard-core functional programming)
  • SBT - scala’s build tool. But scala can also be built with maven etc.

IDEs

  • Intellj Scala plugin available from standard JetBrains repo - just open “settings” and search for / install the plugin.
  • When creating first scala project, will be prompted for “scala SDK” - select “create” then “download”. Or install Scala manually locally, then select that install location.
  • for intellij+mac, the “scala console” evaluates expressions only after cmd-enter has been pressed.

References