Skip to content

Instantly share code, notes, and snippets.

@scotthaleen
Created September 19, 2017 03:05
Show Gist options
  • Select an option

  • Save scotthaleen/83efbf810cd21d95820a0d60ace0cfe6 to your computer and use it in GitHub Desktop.

Select an option

Save scotthaleen/83efbf810cd21d95820a0d60ace0cfe6 to your computer and use it in GitHub Desktop.
scala style

Inference

Use type inference where possible, but put clarity first, and favour explicitness in public APIs.

Almost never annotate the type of a private field or a local variable

All public methods should have explicit type annotations.

public val name: String = "Daniel"

private val name = "Daniel"

public def foo(): String => ... 

Function Values

Prefer type inferance when using anonymous function

val ls: List[String] = ...
ls map (str => str.toInt)

In cases where Scala already knows the type of the function value we are declaring, there is no need to annotate the parameters (in this case, str). This is an intensely helpful inference and should be preferred whenever possible. Note that implicit conversions which operate on function values will nullify this inference, forcing the explicit annotation of parameter types.

Annotations

Type annotations should be

// yes
value: Type

// no
value :Type

Ascription

Ascription follows the type annotation conventions; a space follows the colon and is not used commonly

Type ascription is often confused with type annotation, as the syntax in Scala is identical. The following are examples of ascription:

Nil: List[String]

Set(values: _*)

"Daniel": AnyRef

Ascription is basically just an up-cast performed at compile-time for the sake of the type checker. Its use is not common, but it does happen on occasion. The most often seen case of ascription is invoking a varargs method with a single Seq parameter. This is done by ascribing the _* type (as in the second example above).

Functions

Function types should be declared with a space between the parameter type, the arrow and the return type
Parentheses should be omitted wherever possible (e.g. methods of arity-1, such as Int => String).

def foo(f: Int => String) = ...

def bar(f: (Boolean, Double) => List[String]) = ...

Arity-1

Scala has a special syntax for declaring types for functions of arity-1. The parentheses maybe ommited from the Type to improve readability, for example:

def map[B](f: A => B) = ...
// wrong!
def foo(f: (Int) => (String) => (Boolean) => Double) = ...

// right!
def foo(f: Int => String => Boolean => Double) = ...

Structural Types

Structural types should be declared on a single line if they are less than 50 characters in length.

Structural types are implemented with reflection at runtime, and are inherently less performant than nominal types. Developers should prefer the use of nominal types, unless structural types provide a clear benefit.

When declaring structural types inline, each member should be separated by a semi-colon and a single space, the opening brace should be followed by a space while the closing brace should be preceded by a space.

// wrong!
def foo(a: { def bar(a: Int, b: Int): String; val baz: List[String => String] }) = ...

// right!
private type FooParam = {
  val baz: List[String => String]
  def bar(a: Int, b: Int): String
}

def foo(a: FooParam) = ...

// ok, less than 50 characters

def foo(a: { val bar: String }) = ...

Overview

No spaces between invocation target and dot ( . )
No spaces between method and argument delimeter (parentheses)
Spaces following each agument, after the comma

  // Yes 
  foo(42, bar)
  target.foo(42, bar)
  target.foo()
  
  // No 
  foo (42, bar)
  foo(42,bar)
  target. foo(42, bar)
  target. foo () 

For named parameters there should be a space following the assignment and a space following the comma

  // Yes
  foo(x = 6, y = 7)

  // No
  foo(x=6, y=7)
  foo(x = 6,y = 7)

Arity-0

Omitting parentheses should only be used for purely-functional with outside effects

// no side-effects
list.size 

// side-effects
println()

Infix notation

Scala has a special punctuation-free syntax for invoking methods that take one argument.

Use punctuation-free for symbols but not alphabetic-named methods, a grey area is when the alphabetic-name is short like max

// recommended
a + b

// legal, but less readable
a+b

// legal, but definitely strange
a.+(b)

// recommended
names.mkString(",")

// also sometimes seen; controversial
names mkString ","

// fairly common
a max b

Postfix Notation

Scala allows methods that take no arguments to be invoked using postfix notation:

This style is unsafe, and should not be used. It is considered deprecated

// recommended
names.toList

// discourage
names toList



names toList
val answer = 42        // will not compile!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment