43

By day I write C#. Everything I do goes through Microsoft code analysis and static analysis tools, so my C# has a very regular structure and layout. Obviously, I write code with a certain style. It is partially, because I have no choice (it won't compile if I miss out a space before that comma), but it's also nice to have regular looking code, knowing where to look for things, etc.

At the weekends I'm getting into Scala. Looking at the Scala API and Lift web framework source, I can't obviously see any standardised style. One thing that jumps out at me, for example, is the lack of a separate file per class. The lack of consistency with brackets and braces is another example.

I understand that there are probably a few reasons driving this: firstly, with open source (or hobby) code making sure that an obvious method isn't completely documented is less of a priority. Secondly, things like case classes cut down 20-line class declarations into a single line. Thirdly, C# is a much 'flatter' language: unless it's a complex LINQ statement, the numbers of nested parens, braces and brackets isn't that deep. In Scala, things tend to get a little nested.

Do regular Scala users have a specific style that they stick to? Am I just being stupid putting a one-line case-class in its own file for the sake of [alien] convention? Any tips?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Joe
  • 46,419
  • 33
  • 155
  • 245
  • Mr. Odersky gave a keynote at Scala Days 2013 on `Scala with Style` - http://www.parleys.com/play/51c1994ae4b0d38b54f4621b/chapter0/about – Kevin Meredith Dec 18 '13 at 01:52

5 Answers5

45

Having multiple classes and objects inside a single file is considered good form in Scala, as long as the classes are tightly related.

While not necessary, the type returned by a method -- a named function declared on a trait, class or object -- is expected to be declared for non-private methods. Spaces are expected after :, but not before it.

//  methods declared on a class, trait or object
def length: Int = ...
def multiply(other: Foo): Foo = ...

def hypotenuse(a: Double, b: Double): Double = {
  //  function inside a method, so effectively private
  def square(x: Double) = x * x

  math.sqrt(square(a) + square(b))
}

Spaces are expected between keywords and parenthesis, but not between a method name and the following parenthesis, in dot notation. For operator notation, there doesn't seem to be an accepted style regarding parenthesis -- or when to use that notation, for that matter, but spaces are expected around non-alphanumeric methods in such notation.

//  keywords
if (foo) ...

//  dot notation
foo.doSomething(bar)

//  operator notation
foo doSomething bar
foo + bar

Exceptionally, when concatenating strings with +, the recommended style is not to use spaces around it. For example:

//  concatenate strings
println("Name: "+person.name+"\tAge: "+person.age)

Declarations that can be one-liners are expected to be one-liners, unless the nesting isn't obvious.

//  one-liners
lazy val foo = calculateFoo
def square(x: Int) = x * x

Methods that do not expect parameters, and do not have side effects, are supposed to be used without parenthesis, except for Java methods, which are expected to be used with parenthesis. Parameter-less methods with side effects are supposed to be used with parenthesis.

//  without side-effects
val x = foo.length
val y = bar.coefficient

//  with side-effects
foo.reverse()

Declarations which contains a single expression are expected not to be enclosed inside curly braces unless other syntactic considerations make that impossible. Enclosing an expression within parenthesis to enable multi-line expressions is accepted, but I have seen little use of that.

//  single-line expression
def sum(list: List[Int]): Int = if (!list.isEmpty) list reduceLeft (_ + _) else 0

//  multi-line expression
val sum = (
  getItems
  reduceLeft (_ + _)
)

In for-comprehensions, keeping generators and conditions vertically aligned seems to be an accepted style. As for yield, I have seen it both aligned with for and indented.

//  for-comprehensions
val squares =
  for (x <- numbers)
    yield x * x

// Curly brackets-style identation
val cells = for {
  x <- columns
  y <- rows
  if x != y
} yield Cell(x, y)

// Parameter-style identation
val cells = for (x <- columns;
                 y <- rows;
                 if x != y)
            yield Cell(x, y)

It's also accepted style to vertically align parameters of a class declaration.

Speaking of indentation, two-spaces is the accepted convention.

Curly braces are expected to start on the same line of the declaration, and end vertically aligned with that line by itself.

//  another example
def factorial(n: Int): Int = {
  def fact(n: Int, acc: Int): Int = n match {
    case 0 => acc
    case x => fact(x - 1, x * acc)
  }

  fact(n, 1)
}

For procedures -- functions whose return type is Unit --, the expected style was supposed to be to leave out the type of the method and the equal sign:

//  procedures
def complain {
  println("Oh, no!")
}

Some people think this style is error prone, however, as a missed equal sign will change a function returning something other than Unit into a procedure.

Identifiers are written in camel case (eg: identifiersHaveHumps), like in Java. For names of fields, method parameters, local variables and functions, start with a lower case letter. For classes,traits and types, start with an upper case letter.

Departing from Java convention are constant names. In Scala, the practice is to use standard camel case starting with an upper case letter. For example Pi and not PI, XOffset and not X_OFFSET. This rule is usually followed by any singleton. Having a constants and singletons be represented that way has a practical consequence, for case matches:

import scala.Math.Pi

val pi = Pi // this identifier will be shadowed by the identifier in the function below

def isPi(n: Double): Boolean = n match {
  case Pi => println("I got a true Pi."); true
  case pi => println("I got "+pi+" and bounded it to an identifier named pi."); false
}

Package names are written beginning with a lower case letter. This is particularly helpful when distinguishing in an import statement what is a package and what is not. In the previous example, Math is not a package (it's a singleton), as it begins with an upper case letter.

Using the underline character -- _ -- is not recommended, as that character has many special meanings in Scala. These rules for identifiers can be found on pages 141 and 142 of Programming in Scala, by Odersky, Spoon & Venners.

Right now, I can't recall other situations, but feel free to ask for clarification on specific points. Some of these rules were explicitly stated, others are more of a community consensus. I tried to leave out my own preferences, but I may have failed.

More importantly, perhaps, there just isn't really much of an unified convention. One reason for that may be that Scala is attracting people from many very different backgrounds, such as functional language mavens, Java programmers and web 2.0 enthusiasts.

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
  • 3
    Actually, I think the "leave out the equals" style is *less* error prone since it is effectively a short-hand for explicitly annotating Unit. The intent is very clear, and it is much more concise than an explicit annotation. It is worth noting though that *all* side-effecting methods should be declared with parentheses, especially including those of arity-1. Parentheses-less methods are *only* for pure functions and logical property accessors. – Daniel Spiewak Aug 15 '09 at 16:48
  • Ok, I'll correct the answer. In fact, I'll make it community. However, there was some discussion about making parameter-less methods and functions *not* use parenthesis in all cases. – Daniel C. Sobral Aug 15 '09 at 18:19
  • 4
    In fact, the Programming in Scala book recommends that you can leave out the parenthesis of a method if the method has no arguments *and* has no side effects (e.g. when accessing the state of an object). Therefore, a call like `println()` should still have the parenthesis, but `queue.size` or `array.length` doesn't (see the Uniform access principle - http://en.wikipedia.org/wiki/Uniform_access_principle). The latter example would be `queue.size()` and `array.length` in java, which doesn't respect this principle. – Flaviu Cipcigan Aug 15 '09 at 18:19
  • A nice answer, that could do with more examples. Do you mind if I add some? – Marcus Downing Sep 04 '09 at 20:20
  • This is a community wiki. Go ahead. – Daniel C. Sobral Sep 04 '09 at 22:22
  • Done. Do you want to check the section on for-comprehensions, and fill in the section on classes? – Marcus Downing Sep 06 '09 at 16:05
  • @Marcus Downing: the multi-line expression example is incorrect. I'll fix it. – Daniel C. Sobral Sep 07 '09 at 01:12
  • Why do you call `square` a function? – nafg Apr 16 '13 at 04:29
  • 1
    @nafg I have no idea what my intent was, but I certainly don't agree with what is being said, so I'll fix it. – Daniel C. Sobral Apr 16 '13 at 13:49
  • Would be nice if someone could add something about naming files that contain multiple classes. – Jens Schauder May 10 '13 at 13:06
12

There is now a full Scala style guide which has been proposed to the community. It isn't even remotely official yet, but it is the only (to my knowledge) codification of the community-accepted conventions.

Daniel Spiewak
  • 54,515
  • 14
  • 108
  • 120
7

Now Scala Style Guide is available. It's not 100% official (located on "Community-driven documentation for Scala" site) but seems the most standard style guide for Scala.

kolen
  • 2,752
  • 2
  • 27
  • 35
2

This is a very important question. Generally, Scala style seems to be picked up just by hanging out with other members of the Scala community, reading Scala source code, etc. That's not very helpful for newcomers to the language, but it does indicate that some sort of de facto standard does exist (as chosen by the wisdom of the masses). I am currently working on a fully-realized style guide for Scala, one which documents the community-chosen conventions and best-practices. However, a) it's not finished yet, and b) I'm not sure yet that I'll be allowed to publish it (I'm writing it for work).

To answer your second question (sort of): in general, each class/trait/object should get its own file named according to Java naming conventions. However, in situations where you have a lot of classes which share a single common concept, sometimes it is easiest (both in the short-term and in the long-term) to put them all into the same file. When you do that, the name of the file should start with a lower-case letter (still camelCase) and be descriptive of that shared concept.

Daniel Spiewak
  • 54,515
  • 14
  • 108
  • 120
  • Do, please, indicate any errors in my answer. I do not want to propagate erroneous style information -- we are disperse enough as it is. – Daniel C. Sobral Aug 15 '09 at 15:03
2

I don't really care for the typical style that many of the Scala coders use, so I just apply the same standard I would using in C#, Java or especially JavaScript.

Scala can be very expressive, but using an unfamiliar format will increase your barrier to entry. Especially considering internal DSLs, which could not possibly have a "Standard".

So, I say to do whatever make your code more readable to you and your team.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Erick Fleming
  • 1,270
  • 1
  • 9
  • 17