Generally speaking, Scala uses “camel case” naming. That is,each word is capitalized, except possibly the first word:
UpperCamelCase
lowerCamelCase
Acronyms should be treated as normal words:
Xhtml
maxId
instead of:
XHTML
maxID
Underscores in names (_
) are not actually forbidden by thecompiler, but are strongly discouraged as they havespecial meaning within the Scala syntax. (But see belowfor exceptions.)
Classes/Traits
Classes should be named in upper camel case:
class MyFairLady
This mimics the Java naming convention for classes.
Sometimes traits and classes as well as their members are used to describeformats, documentation or protocols and generate/derive them. In these cases it is desirable to be close to a 1:1 relation to the output formatand the naming conventions don’t apply. In this case, they should only be usedfor that specific purpose and not throughout the rest of the code.
Objects
Object names are like class names (upper camel case).
An exception is when mimicking a package or function.This isn’t common. Example:
object ast {
sealed trait Expr
case class Plus(e1: Expr, e2: Expr) extends Expr
...
}
object inc {
def apply(x: Int): Int = x + 1
}
Packages
Scala packages should follow the Java package naming conventions:
// wrong!
package coolness
// right! puts only coolness._ in scope
package com.novell.coolness
// right! puts both novell._ and coolness._ in scope
package com.novell
package coolness
// right, for package object com.novell.coolness
package com.novell
/**
* Provides classes related to coolness
*/
package object coolness {
}
root
It is occasionally necessary to fully-qualify imports usingroot
. For example if another net
is in scope, thento access net.liftweb
we must write e.g.:
import _root_.net.liftweb._
Do not overuse root
. In general, nested package resolves are agood thing and very helpful in reducing import clutter. Using root
not only negates their benefit, but also introduces extra clutter in andof itself.
Methods
Textual (alphabetic) names for methods should be in lower camel case:
def myFairMethod = ...
This section is not a comprehensive guide to idiomatic method naming in Scala.Further information may be found in the method invocation section.
Accessors/Mutators
Scala does not follow the Java convention of prepending set
/get
tomutator and accessor methods (respectively). Instead, the followingconventions are used:
- For accessors of properties, the name of the method should be thename of the property.
- In some instances, it is acceptable to prepend “
is
” on a booleanaccessor (e.g.isEmpty
). This should only be the case when nocorresponding mutator is provided. Please note that theLift convention of appending “_?
” to booleanaccessors is non-standard and not used outside of the Liftframework. - For mutators, the name of the method should be the name of theproperty with “
_=
” appended. As long as a corresponding accessorwith that particular property name is defined on the enclosing type,this convention will enable a call-site mutation syntax whichmirrors assignment. Note that this is not just a convention but arequirement of the language.
class Foo {
def bar = ...
def bar_=(bar: Bar) {
...
}
def isBaz = ...
}
val foo = new Foo
foo.bar // accessor
foo.bar = bar2 // mutator
foo.isBaz // boolean property
Unfortunately, these conventions fall afoul of the Java conventionto name the private fields encapsulated by accessors and mutatorsaccording to the property they represent. For example:
public class Company {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
In Scala, there is no distinction between fields and methods. In fact,fields are completely named and controlled by the compiler. If we wantedto adopt the Java convention of bean getters/setters in Scala, this is arather simple encoding:
class Company {
private var _name: String = _
def name = _name
def name_=(name: String) {
_name = name
}
}
While Hungarian notation is terribly ugly, it does have the advantage ofdisambiguating the name
variable without cluttering the identifier.The underscore is in the prefix position rather than the suffix to avoidany danger of mistakenly typing name
instead of name_
. With heavyuse of Scala’s type inference, such a mistake could potentially lead toa very confusing error.
Note that the Java getter/setter paradigm was often used to work around alack of first class support for Properties and bindings. In Scala, thereare libraries that support properties and bindings. The convention is touse an immutable reference to a property class that contains its owngetter and setter. For example:
class Company {
val string: Property[String] = Property("Initial Value")
Parentheses
Unlike Ruby, Scala attaches significance to whether or not a method isdeclared with parentheses (only applicable to methods ofarity-0). For example:
def foo1() = ...
def foo2 = ...
These are different methods at compile-time. While foo1
can be calledwith or without the parentheses, foo2
may not be called _with_parentheses.
Thus, it is actually quite important that proper guidelines be observedregarding when it is appropriate to declare a method without parenthesesand when it is not.
Methods which act as accessors of any sort (either encapsulating a fieldor a logical property) should be declared without parentheses exceptif they have side effects. While Ruby and Lift use a !
to indicatethis, the usage of parens is preferred (please note that fluid APIs andinternal domain-specific languages have a tendency to break theguidelines given below for the sake of syntax. Such exceptions shouldnot be considered a violation so much as a time when these rules do notapply. In a DSL, syntax should be paramount over convention).
Further, the callsite should follow the declaration; if declared withparentheses, call with parentheses. While there is temptation to save afew characters, if you follow this guideline, your code will be _much_more readable and maintainable.
// doesn't change state, call as birthdate
def birthdate = firstName
// updates our internal state, call as age()
def age() = {
_age = updateAge(birthdate)
_age
}
Symbolic Method Names
Avoid! Despite the degree to which Scala facilitates this area of APIdesign, the definition of methods with symbolic names should not beundertaken lightly, particularly when the symbols itself arenon-standard (for example, >>#>>
). As a general rule, symbolic methodnames have two valid use-cases:
- Domain-specific languages (e.g.
actor1 ! Msg
) - Logically mathematical operations (e.g.
a + b
orc :: d
)
In the former case, symbolic method names may be used with impunity solong as the syntax is actually beneficial. However, in the course ofstandard API design, symbolic method names should be strictly reservedfor purely-functional operations. Thus, it is acceptable to define a>>=
method for joining two monads, but it is not acceptable to definea <<
method for writing to an output stream. The former ismathematically well-defined and side-effect free, while the latter isneither of these.
As a general rule, symbolic method names should be well-understood andself documenting in nature. The rule of thumb is as follows: if you needto explain what the method does, then it should have a real, descriptivename rather than a symbols. There are some very rare cases where it isacceptable to invent new symbolic method names. Odds are, your API isnot one of those cases!
The definition of methods with symbolic names should be considered anadvanced feature in Scala, to be used only by those most well-versed inits pitfalls. Without care, excessive use of symbolic method names caneasily transform even the simplest code into symbolic soup.
Constants, Values, Variable and Methods
Constant names should be in upper camel case. Similar to Java’s static final
members, if the member is final, immutable and it belongs to a packageobject or an object, it may be considered a constant:
object Container {
val MyConstant = ...
}
The value: Pi
in scala.math
package is another example of such a constant.
Method, Value and variable names should be in lower camel case:
val myValue = ...
def myMethod = ...
var myVariable
Type Parameters (generics)
For simple type parameters, a single upper-case letter (from the Englishalphabet) should be used, starting with A
(this is different than theJava convention of starting with T
). For example:
class List[A] {
def map[B](f: A => B): List[B] = ...
}
If the type parameter has a more specific meaning, a descriptive nameshould be used, following the class naming conventions (as opposed to anall-uppercase style):
// Right
class Map[Key, Value] {
def get(key: Key): Value
def put(key: Key, value: Value): Unit
}
// Wrong; don't use all-caps
class Map[KEY, VALUE] {
def get(key: KEY): VALUE
def put(key: KEY, value: VALUE): Unit
}
If the scope of the type parameter is small enough, a mnemonic can beused in place of a longer, descriptive name:
class Map[K, V] {
def get(key: K): V
def put(key: K, value: V): Unit
}
Higher-Kinds and Parameterized Type parameters
Higher-kinds are theoretically no different from regular type parameters(except that theirkind) is at least=>
rather than simply *
). The naming conventions are generallysimilar, however it is preferred to use a descriptive name rather than asingle letter, for clarity:
class HigherOrderMap[Key[_], Value[_]] { ... }
The single letter form is (sometimes) acceptable for fundamental conceptsused throughout a codebase, such as F[]
for Functor and M[
]
forMonad.
In such cases, the fundamental concept should be something well knownand understood to the team, or have tertiary evidence, such as thefollowing:
def doSomething[M[_]: Monad](m: M[Int]) = ...
Here, the type bound : Monad
offers the necessary evidence to informthe reader that M[_]
is the type of the Monad.
Annotations
Annotations, such as @volatile
should be in lower camel case:
class cloneable extends StaticAnnotation
This convention is used throughout the Scala library, even though it isnot consistent with Java annotation naming.
Note: This convention applied even when using type aliases onannotations. For example, when using JDBC:
type id = javax.persistence.Id @annotation.target.field
@id
var id: Int = 0
Special Note on Brevity
Because of Scala’s roots in the functional languages, it is quite normalfor local names to be very short:
def add(a: Int, b: Int) = a + b
This would be bad practice in languages like Java, but it is _good_practice in Scala. This convention works because properly-written Scalamethods are quite short, only spanning a single expression and rarelygoing beyond a few lines. Few local names are used (includingparameters), and so there is no need to contrive long, descriptivenames. This convention substantially improves the brevity of most Scalasources. This in turn improves readability, as most expressions fit inone line and the arguments to methods have descriptive type names.
This convention only applies to parameters of very simple methods (andlocal fields for very simply classes); everything in the publicinterface should be descriptive. Also note that the names of argumentsare now part of the public API of a class, since users can use namedparameters in method calls.