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 => ... 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.
Type annotations should be
// yes
value: Type
// no
value :TypeAscription 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": AnyRefAscription 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).
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]) = ...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 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 }) = ...
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)Omitting parentheses should only be used for purely-functional with outside effects
// no side-effects
list.size
// side-effects
println()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 bScala 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!