Classes

Class/Object/Trait constructors should be declared all on one line,unless the line becomes “too long” (about 100 characters). In that case,put each constructor argument on its own line withtrailing commas:

  1. class Person(name: String, age: Int) {
  2. }
  3. class Person(
  4. name: String,
  5. age: Int,
  6. birthdate: Date,
  7. astrologicalSign: String,
  8. shoeSize: Int,
  9. favoriteColor: java.awt.Color,
  10. ) {
  11. def firstMethod: Foo =
  12. }

If a class/object/trait extends anything, the same general rule applies,put it on one line unless it goes over about 100 characters, and thenput each item on its own line withtrailing commas;closing parenthesis provides visual separation between constructor arguments and extensions;empty line should be added to further separate extensions from class implementation:

  1. class Person(
  2. name: String,
  3. age: Int,
  4. birthdate: Date,
  5. astrologicalSign: String,
  6. shoeSize: Int,
  7. favoriteColor: java.awt.Color,
  8. ) extends Entity
  9. with Logging
  10. with Identifiable
  11. with Serializable {
  12. def firstMethod: Foo =
  13. }

Ordering Of Class Elements

All class/object/trait members should be declared interleaved withnewlines. The only exceptions to this rule are var and val. Thesemay be declared without the intervening newline, but only if none of thefields have Scaladoc and if all of the fields have simple (max of 20-ishchars, one line) definitions:

  1. class Foo {
  2. val bar = 42
  3. val baz = "Daniel"
  4. def doSomething(): Unit = { ... }
  5. def add(x: Int, y: Int): Int = x + y
  6. }

Fields should precede methods in a scope. The only exception is if theval has a block definition (more than one expression) and performsoperations which may be deemed “method-like” (e.g. computing the lengthof a List). In such cases, the non-trivial val may be declared at alater point in the file as logical member ordering would dictate. Thisrule only applies to val and lazy val! It becomes very difficultto track changing aliases if var declarations are strewn throughoutclass file.

Methods

Methods should be declared according to the following pattern:

  1. def foo(bar: Baz): Bin = expr

Methods with default parameter values should be declared in an analogousfashion, with a space on either side of the equals sign:

  1. def foo(x: Int = 6, y: Int = 7): Int = x + y

You should specify a return type for all public members.Consider it documentation checked by the compiler.It also helps in preserving binary compatibility in the face of changing type inference (changes to the method implementation may propagate to the return type if it is inferred).

Local methods or private methods may omit their return type:

  1. private def foo(x: Int = 6, y: Int = 7) = x + y

Procedure Syntax

Avoid the procedure syntax, as it tends to be confusing for very little gain in brevity.

  1. // don't do this
  2. def printBar(bar: Baz) {
  3. println(bar)
  4. }
  5. // write this instead
  6. def printBar(bar: Bar): Unit = {
  7. println(bar)
  8. }

Modifiers

Method modifiers should be given in the following order (when each isapplicable):

  • Annotations, each on their own line
  • Override modifier (override)
  • Access modifier (protected, private)
  • Implicit modifier (implicit)
  • Final modifier (final)
  • def
  1. @Transaction
  2. @throws(classOf[IOException])
  3. override protected final def foo(): Unit = {
  4. ...
  5. }

Body

When a method body comprises a single expression which is less than 30(or so) characters, it should be given on a single line with the method:

  1. def add(a: Int, b: Int): Int = a + b

When the method body is a single expression longer than 30 (or so)characters but still shorter than 70 (or so) characters, it should begiven on the following line, indented two spaces:

  1. def sum(ls: List[String]): Int =
  2. ls.map(_.toInt).foldLeft(0)(_ + _)

The distinction between these two cases is somewhat artificial.Generally speaking, you should choose whichever style is more readableon a case-by-case basis. For example, your method declaration may bevery long, while the expression body may be quite short. In such a case,it may be more readable to put the expression on the next line ratherthan making the declaration line too long.

When the body of a method cannot be concisely expressed in a single lineor is of a non-functional nature (some mutable state, local orotherwise), the body must be enclosed in braces:

  1. def sum(ls: List[String]): Int = {
  2. val ints = ls map (_.toInt)
  3. ints.foldLeft(0)(_ + _)
  4. }

Methods which contain a single match expression should be declared inthe following way:

  1. // right!
  2. def sum(ls: List[Int]): Int = ls match {
  3. case hd :: tail => hd + sum(tail)
  4. case Nil => 0
  5. }

Not like this:

  1. // wrong!
  2. def sum(ls: List[Int]): Int = {
  3. ls match {
  4. case hd :: tail => hd + sum(tail)
  5. case Nil => 0
  6. }
  7. }

Multiple Parameter Lists

In general, you should only use multiple parameter lists if there is agood reason to do so. These methods (or similarly declared functions)have a more verbose declaration and invocation syntax and are harder forless-experienced Scala developers to understand.

There are three main reasons you should do this:

  • For a fluent API

Multiple parameter lists allow you to create your own “controlstructures”:

  1. def unless(exp: Boolean)(code: => Unit): Unit = if (!exp) code
  2. unless(x < 5) {
  3. println("x was not less than five")
  4. }
  • Implicit Parameters

When using implicit parameters, and you use the implicit keyword,it applies to the entire parameter list. Thus, if you want only someparameters to be implicit, you must use multiple parameter lists.

  • For type inference

When invoking a method using only some of the parameter lists, thetype inferencer can allow a simpler syntax when invoking theremaining parameter lists. Consider fold:

  1. def foldLeft[B](z: B)(op: (B, A) => B): B
  2. List("").foldLeft(0)(_ + _.length)
  3. // If, instead:
  4. def foldLeft[B](z: B, op: (B, A) => B): B
  5. // above won't work, you must specify types
  6. List("").foldLeft(0, (b: Int, a: String) => b + a.length)
  7. List("").foldLeft[Int](0, _ + _.length)

For complex DSLs, or with type-names that are long, it can be difficultto fit the entire signature on one line. In those cases, align theopen-paren of the parameter lists, one list per line (i.e. if you can’tput them all on one line, put one each per line):

  1. protected def forResource(resourceInfo: Any)
  2. (f: (JsonNode) => Any)
  3. (implicit urlCreator: URLCreator, configurer: OAuthConfiguration): Any = {
  4. ...
  5. }

Higher-Order Functions

It’s worth keeping in mind when declaring higher-order functions thefact that Scala allows a somewhat nicer syntax for such functions atcall-site when the function parameter is curried as the last argument.For example, this is the foldl function in SML:

  1. fun foldl (f: ('b * 'a) -> 'b) (init: 'b) (ls: 'a list) = ...

In Scala, the preferred style is the exact inverse:

  1. def foldLeft[A, B](ls: List[A])(init: B)(f: (B, A) => B): B = ...

By placing the function parameter last, we have enabled invocationsyntax like the following:

  1. foldLeft(List(1, 2, 3, 4))(0)(_ + _)

The function value in this invocation is not wrapped in parentheses; itis syntactically quite disconnected from the function itself(foldLeft). This style is preferred for its brevity and cleanliness.

Fields

Fields should follow the declaration rules for methods, taking specialnote of access modifier ordering and annotation conventions.

Lazy vals should use the lazy keyword directly before the val:

  1. private lazy val foo = bar()

Function Values

Scala provides a number of different syntactic options for declaringfunction values. For example, the following declarations are exactlyequivalent:

  • val f1 = ((a: Int, b: Int) => a + b)
  • val f2 = (a: Int, b: Int) => a + b
  • val f3 = (: Int) + (: Int)
  • val f4: (Int, Int) => Int = ( + )Of these styles, (1) and (4) are to be preferred at all times. (2)appears shorter in this example, but whenever the function value spansmultiple lines (as is normally the case), this syntax becomes extremelyunwieldy. Similarly, (3) is concise, but obtuse. It is difficult for theuntrained eye to decipher the fact that this is even producing afunction value.

When styles (1) and (4) are used exclusively, it becomes very easy todistinguish places in the source code where function values are used.Both styles make use of parentheses, since they look clean on a single line.

Spacing

There should be no space between parentheses and the code they contain.Curly braces should be separated from the code within them by a one-space gap,to give the visually busy braces “breathing room”.

Multi-Expression Functions

Most function values are less trivial than the examples given above.Many contain more than one expression. In such cases, it is often morereadable to split the function value across multiple lines. When thishappens, only style (1) should be used, substituting braces for parentheses.Style (4) becomes extremely difficult to follow when enclosed in large amountsof code. The declaration itself should loosely follow the declaration style formethods, with the opening brace on the same line as the assignment orinvocation, while the closing brace is on its own line immediatelyfollowing the last line of the function. Parameters should be on thesame line as the opening brace, as should the “arrow” (=>):

  1. val f1 = { (a: Int, b: Int) =>
  2. val sum = a + b
  3. sum
  4. }

As noted earlier, function values should leverage type inferencewhenever possible.