Luet oppimateriaalin englanninkielistä versiota. Mainitsit kuitenkin taustakyselyssä osaavasi suomea. Siksi suosittelemme, että käytät suomenkielistä versiota, joka on testatumpi ja hieman laajempi ja muutenkin mukava.

Suomenkielinen materiaali kyllä esittelee englanninkielisetkin termit. Myös suomenkielisessä materiaalissa käytetään ohjelmaprojektien koodissa englanninkielisiä nimiä kurssin alkupään johdantoesimerkkejä lukuunottamatta.

Voit vaihtaa kieltä A+:n valikon yläreunassa olevasta painikkeesta. Tai tästä: Vaihda suomeksi.


Style Guide

About This Page:

Questions Answered How can I make my program code easier to read and edit? How should I indent my Scala code; which functions should have brackets; what about lower- and upper-case letters?

Topics: An introduction to programming style and style conventions. Some considerations for formatting Scala code.

Prerequisites: Much of this guide should be understandable after Week 3 of O1 and almost all after Week 4. There are a few points that concern later topics.

Introduction: Why?

Good programming style makes programs easier for humans to read and understand. A well-written program is less likely to have bugs, and it’s less work to develop it further.

The computer doesn’t clear about readability. In principle, the two class definitions below do basically the same thing:

class
game
(
val


avocados       :Team,val vi:                   Team,val
  m1:Int,M2:
     Int){def
     Which={if(m1>this
                                                                .
      M2)Some(
  this.avocados)else if(M2
    > this.m1)
      Some(this.vi) else None
                           }}
/* Each Match object represents a match between two sports
 * teams that play one another, each seeking to score goals. */
class Match(val homeTeam: Team,
            val awayTeam: Team,
            val homeGoals: Int,
            val awayGoals: Int) {

    /* Returns the winning team, or None in case the match
     * is a draw. */
    def winner = {
      if (this.homeGoals > this.awayGoals)
        Some(this.homeTeam)
      else if (this.awayGoals > this.homeGoals)
        Some(this.awayTeam)
      else
        None
    }

}

In practice, the two classes don’t do the same thing, since the first class is so awfully written that a you’d never want to use it in a program.

Sure, that example is over-dramatic, given how atrocious the first class definition is. But smaller, accidental violations of good programming style can also make the programmer’s work harder or at least slow them down.

Successful programs survive by evolving: they get edited and further developed time and time again. As a program grows to hundreds, thousands, or even millions of lines of code, good programming style becomes increasingly important. Even a lone programmer cannot recall precisely what they’ve thought and done a month or a year ago; it can be surprisingly difficult to modify one’s own poorly written code. Not to mention that many programmers work on legacy code and develop software in teams: one had better hope that the other programmers bothered to make their code easy to work with.

Many things affect how readable and modifiable a program is. High-level design matters, of course: How has the programmer designed the program’s structure and broken the whole down into logical components: Which classes and methods have been identified to model the program’s domain? Is the program designed in imperative or functional “style”? And so forth.

On this page, we’ll restrict our discussion on relatively superficial aspects of style, which are nevertheless also important. In the text that follows, programming style refers to “code-writing style”: the decisions we make about how to phrase a particular program design as text. In these terms, the two classes above have the same design but thoroughly different in programming style.

Style Conventions

Each programming language is typically associated with its own style conventions (or coding conventions) that suggest how to format programs written in that language. It’s common that a single language has several alternative sets of conventions that specify somewhat different styles of writing programs.

Scala, too, has its own semi-official style guidelines, which isn’t unanimously accepted or followed by all Scala programmers. This style guide for O1 largely conforms to those general guidelines but deviates from it in some details.

There is no One True Style to write programs in a language. In O1, we don’t require you to follow any specific set of coding conventions. But it is important that when you write a program, you write it in some consistent way. Without being consistent, it’s difficult or impossible to react the goal: clarity.

Some of the other programming courses at Aalto follow somewhat different conventions for Scala than we do in O1. And if you read Scala programs published online, you’ll find that they are written in a variety of styles. You should therefore learn to:

  • follow some reasonable programming style yourself; and
  • tolerate and understand code written in other reasonable styles.

It’s fine to break with convention sometimes, once you know what you’re doing and judge it as appropriate,

How to Improve Readability in Practice?

When formatting your code for readability, some of the key considerations are:

  • the use of whitespace, indentation in particular;
  • writing comments where appropriate; and
  • giving meaningful names to program components.

See below for more detailed suggestions.

Style Basics: Using Whitespace

A program written in, say, Scala has a hierarchical structure. There are files that contain class definitions. Those classes in turn define variables and methods. The method definitions contain commands, many of which are a combination of other commands.

We can format our code to make that structure apparent. In Scala and many other languages, the convention is to indent lines of code.

As an example, compare the two (otherwise pointless) fragments of code. They only differ from each other in how they’re indented and use whitespace (line breaks and space characters). You’ll probably agree that the second version is nicer to read than the first.

class ExampleClass(val example:AnotherClass,var anotherExample:Int){
def myMethod()={
while(this.example.checkIfDone()){
this.doSomething()
if(this.example.checkState()){
this.doSomethingMuuta()
this.anotherExample+=1
}else{
this.example.changeStuff()
}
}
}
def anotherMethod()={
println(this.example)
}
// ... other methods ...
}
class ExampleClass(val example: AnotherClass, var anotherExample: Int) {

  def myMethod() = {
    while (this.example.checkIfDone()) {
      this.doSomething()
      if (this.example.checkState()) {
        this.doSomethingMuuta()
        this.anotherExample += 1
      } else {
        this.example.changeStuff()
      }
    }
  }

  def anotherMethod() = {
    println(this.example)
  }

  // ... other methods ...
}

Beginner programmers sometimes leave their program unindented as in the first version above or indent their code erratically. Don’t do that.

In Scala, indentations are customarily two spaces wide.

As illustrated above, you can further improve readability with empty lines and additional spaces within lines. It’s generally a good idea to leave a blank line between methods that span multiple lines, at least. Even within a single method, you can consider grouping lines together much like you might group natural language into paragraphs. However, if your method is more than a few lines in length, you should seriousy consider splitting it in multiple methods, each dedicated to a single purpose.

Style Basics: Commenting Your Code

The fact that you can write Comments that help human readers came up already in Chapter 1.2.

Comments can be good or bad; it depends.

Comments that document the purpose of a program component and the interface for using that component are often a good idea:

  • What concept does a class definition represent? How can a programmer use the class?
  • What does each of the class’s public methods achieve? What does the method expect as a parameter? What can the method’s caller expect as a return value? Are there any special cases that the caller should be aware of?

Such documentation comments should be written to help programmers use the interface without having to know the underlying implementation. O1’s example projects contain many examples.

Documenting methods’ implementations — the commands that are executed when the method runs — is sometimes a good idea but the urge to write such a comment may also indicate a problem that would be best solved differently. In general, you should try to write your code clearly enough that that implementation-clarifying are needed rarely if at all. If your program is well designed, its components are sensibly named, and each component’s interface is sufficiently documented, your methods will probably to be short and crisp and require little additional explanation.

In O1, you’re not required to comment your code unless specifically requested to do so. You may want to do it nevertheless. Many follow-on courses will require you to write comments, as do many companies and organizations that you might work for in the future.

Style Basics: Naming Things

When choosing an identifier (name) for a program component — class, method, variable, etc. — try to capture the purpose of that component. number and value aren’t generally very informative names for variables. Neither are a, a2, oppAdv, jimmy, and fsdhafsdkjh.

(Of course, when experimenting on a tiny piece of code, generic and short names like number, a, or test are fine.)

Pay attention to the language’s common naming conventions that would confuse readers if violated. For instance, in Scala, start your Scala classes with an upper-case letter and your variables with a lower-case one.

Obviously, you’ll also need to follow any technical restrictions that may apply. You can’t use reserved words as identifiers. The programming language may also impose other limitations; for instance, Scala and many other languages prohibit starting an identifier with a digit.


So far, our discussion of programming style has been mostly generic. Let’s now take a look at some stylistic issues that are particular to Scala.

Scala Style: Naming Things

Upper-case vs. lower-case letters

The first letter of a name should tell the reader something about the name’s referrent:

  • Class names customarily start with an upper-case letter.
  • The names of singleton objects typically start with an upper-case latter, although exceptions may be made (e.g., when the singleton is intended as package object; Chapter 5.2).
  • Variable names customarily start with a lower-case letter.
    • However, variables that are meant as constants are capitalized. A constant’s value is known independently of any program run and represents some “permanent” information. Using constants instead of “magic numbers” is good style (see, e.g., Chapter 2.6).
  • Method names customarily start with a lower-case letter.

In names that consist of multiple words, use upper-case letters to mark the word borders: ClassName, variableName, methodName. Exception: package names are written completely in lower case.

Restrictions on names

Don’t use space characters in identifiers.

Beginners are better off avoiding all special characters (+, &, {, etc.) when naming things. Some special characters have specific meanings in Scala. However, most special characters can be used in names, which may be useful if you’re looking to define a method that’s meant to be used as an operator (Chapter 5.2).

The names of library functions such abs or sqrt aren’t reserved; neither are the names of even the most common type names, such as Int and String. Just because you could in principle name one of your own classes Int doesn’t mean it’s a great idea, though.

Scala Style: Defining Functions

Some of Scala’s more unusual style conventions concern the function definitions.

A function may be either effect-free (free of “side effects”) or effectful. As noted in Chapter 1.7, it is customary in Scala to highlight this difference with punctuation. The purpose of the following style conventions is to help the program’s reader see which functions may impact on state and which functions never do. This is useful to experienced Scala programmers, at least, and may help beginners, too.

The equals sign

Always write an equals sign between the parameter list and the function body.

def sum(first: Int, second: Int) = first + second

Scala does in fact allow you to leave out the equals sign in some cases (i.e., if your function is supposed to return Unit). For instance, this function does work but you should not write your code like this:

def greet(greeting: String) {
  println(greeting)
}

Write this instead:

def greet(greeting: String) = {
  println(greeting)
}

Scala’s developers have indicated that later versions of Scala will require the equals sign in all cases.

Effect-free functions

In effect-free functions, it’s customary to leave out the curly brackets when possible. They are, however, required in case the method body consists of multiple sequential commands, as here:

def result(first: Int, second: Int) = {
  val intermediate = first * 2 + second
  intermediate * intermediate
}

This function has a single-line body, so the curly brackets are unnecessary and are customarily not written:

def sum(first: Int, second: Int) = {
  first + second
}

A simple function such as sum would normally be defined on a single line, as shown earlier.

Effectful functions

In effectful functions, it is customary to always write the curlies, line breaks, and indentation, even if the method body is just a single line:

def printSum(first: Int, second: Int) = {
  println("The sum is: " + (first + second))
}

Summary

This table, replicated from Chapter 1.7, summarizes the conventions just listed. You can mouse over the underlined parts for some clarifications.

Does the function affect state? Does it return a value? The term we use in O1 Use an equals sign in front of the function body? Use curly brackets around the body? Use line breaks and indentations?
Never Yes Effect-free function Yes! At least if the body has multiple commands. Always where you have curly brackets. Also used for splitting long one-liners.
No (If a function doesn’t have an effect on program state or return a value, it can’t be very useful, barring some special circumstances. You won’t need to write such an empty function in O1.)
At least sometimes Yes Effectful function Yes! Yes Yes
No Effectful function Yes Yes Yes

The simple option

In O1, it’s acceptable to put an equals sign, curly brackets, and indentations in all your function definitions. But you can try following the conventions listed above.

A further consideration: parameterless functions

Some functions don’t take any parameters. In Scala, there are two ways to define such a function: you can define a function with an empty parameter list or a function with no parameter list at all.

If a parameterless function is effectful, it’s customary to give it an empty parameter list (Chapter 2.6). Here is an example:

def printStandardText() = {
  println("Note the empty brackets above, which indicate an empty parameter list.")
}

If a parameterless function is effect-free, it’s customary to make it give it no parameter list at all. In practice, this means leaving out the empty brackets, as shown for the mass method below.

class Projectile(val volume: Double, val density: Double) {

  def mass = this.volume * this.density

}

Note that this is a style convention, not a technical requirement enforced by Scala. If you wanted to flout convention, you could give all your parameterless methods an empty parameterless (as is done in some other programming languages).

Whether a function has an empty parameter list or not affects how you may call the function, as discussed below.

Scala Style: Calling Functions

Calling a parameterless function

When you call a parameterless function, you need to heed whether it’s truly parameterless (and effect-free, if the code adheres to convention) or if it has an empty parameter list (and is effectful).

When you call a function that has no parameter list at all, you must write only the function’s name. Do not write empty brackets after the name:

someProjectile.mass     // works
someProjectile.mass()   // doesn’t work

If the function has an empty parameter list, it’s technically possible to either write the empty brackets or omit them as you call the function. Convention dictates that you should prefer the form with the brackets, which highlights the effect on state:

printStandardText()   // works; this is the recommended form
printStandardText     // works but is strongly discouraged

Operator vs. dot notation

As noted in Chapter 5.2, there are two ways to call a single-parameter method in Scala: operator notation and dot notation. For instance, even the so-called “plus operator” is actually a method on a number object, and you can write either 1 + 1 or 1.+(1). Similarly, you can search for an element in a buffer by writing either numbers.indexOf(10) or numbers indexOf 10.

In O1, we generally prefer the dot notation. We only use the operator notation in selected contexts that involve common data types (such as Int) and their common, operator-like methods (such as +).

You should be aware, though, that the operator notation is somewhat more common outside of O1. Some Scala programmers use it when calling higher-order methods, for instance (as discussed at the end of Chapter 6.3).

Scala Style: Type Annotations

Type inference is an inseparable part of the Scala language. Many type annotations are optional in Scala code, as many (static) types can be automatically inferred. Scala programmers frequently leave types implicit unless there is reason to do otherwise.

When defining variables, it’s common to leave out type annotations. The most common exception to this are parameter variables, which require an explicit type. Even where an annotation isn’t required, a programmer may decide to add one for clarity, and that’s fine.

Most functions don’t require an explicit return-type annotation, but there are exceptions, such as overloaded and recursive functions. On the other hand, you can write a return type on any function; such annotations sometimes clarify the code and may prevent some bugs.

Some Scala programmers explicitly mark the type of all public variables and the return type of all public methods.

Occasionally, adding a type annotation results in a clearer compile-time error message as the annotation provides additional information to the compiler.

Scala Style: Using Whitespace

As the grotesque program at the top of this page demonstrates, Scala is pretty liberal about the use of whitespace; most programming languages are. There are some restrictions, though: you can’t add space in the middle of a reserved word, for example, nor is a line break allowed in the middle of a (regular) string literal, etc. If you want the rules in full, you’ll find them in the official definition of the Scala language.

As a general rule, you should avoid writing excessively long lines. (Programmers disagree among themselves as to what is excessive.) For instance, you can split a long list of constructor parameters across multiple lines ass shown in the Match class at the top of the page.

What about the reverse? Can you omit line breaks where you have a sequence of short commands?

Scala does allow you to do that, but you’ll need to insert semicolons between the commands. For instance, this is valid code:

var number = 0; println(number); number += 1; println(number); number += 10; println(number)

When experimenting on small pieces of code (in the REPL, perhaps), programming style matters less and the semicolons may be a handy shortcut. However, you’ll generally want to avoid that style in proper programs. Writing sequential commands on separate lines highlights the program’s flow better.

Scala Style: Using this

If an object’s member variable and a method’s local variable have the same name, you need the keyword this to refer to the object’s variable; there is a small example in Chapter 2.2 that illustrates this. (It sometimes makes sense to use multiple variables with the same name. Of course, you should also consider whether using different names would be clearer.)

The same chapter also offers this advice:

Even when it’s not required, the word this emphasizes where the programmer uses an object’s variables, as opposed to where they use local variables. We recommend that you always use this when referring to an object’s own variables, because it makes the code easier to understand.

To an extent, this is a matter of taste. If you wish — and if you know what you’re doing — go ahead and leave out any this keywords that don’t need to be there. Outside of O1, such omissions are common.

Scala Style: if and match

When selecting, consider whether you’re dealing with a choice between effects or a choice between effect-free expression. The basic idea is the same as for functions: effectful code is split across multiple lines.

Selecting between effects on state

If you have an effectful if statement, surround each branch in curly brackets, even if the branch contains only a single command:

if (number > 0) {
  println("It's positive.")
} else {
  println("It isn't positive.")
}

That is, you should avoid this style even though the code works:

if (number > 0) println("It's positive.") else println("It isn't positive.")

Some effectful ifs don’t need an else branch (Chapter 3.4). Just omit that branch and write the optional effect in curly brackets:

if (number > 0) {
  println("Print this if the number is positive. Otherwise, print nothing.")
}

An effectful match command similarly calls for line breaks and indentations:

possibleValue match {
  case Some(value) =>
    println("The value exists.")
    println("It is: " + value)
  case None =>
    println("There is no value.")
}

Effect-free selection

If you have an effect-free if, check if either of its branches contains multiple consecutive commands. If so, put both branches in brackets as described for the effectful case above.

However, if you have two effect-free branches with a single command in each, you can combine them into a single line:

val result = if (divisor != 0) dividend / divisor else 0

In case such a line would end up being very long, it’s better to split it:

val anotherResult =
  if (firstConditionIsMet && anotherIsMetToo && oneMoreLongCondition && cetera)
    computeResultUsingThisFunctionWithAReallyLongName(number)
  else
    computeResultUsingAnotherFunction(number)

The same logic goes for match. Where you have a single, effect-free expression, you can write it on the same line as the case keyword.

val report = possibleValue match {
  case Some(value) => "The value is: " + value
  case None        => "No value"
}

Scala Style: Function Literals

In Scala, there are different ways to write function literals that define anonymous functions. None of those ways is categorically better than the others or decisively most common among Scala programmers. You should be familiar with the different notations, but you can certainly favor one of them in your own code. See Chapter 6.2 for a discussion.

Scala Style: Looping with while, do, and for

The while and do keywords (Chapter 8.3) define loops whose purpose is to affect the program’s state. Moreover, all the for loops that appear in O1’s official materials are likewise effectful.

Format such effectful loops like you format effectful if statements: use line breaks and curly brackets. For instance, here is a while loop:

while (conditionHolds()) {
  keepDoingStuff()
}

Don’t write this (even though it works):

while (conditionHolds()) keepDoingStuff()

Summary of Key Points

  • Programs written in a good style are easier to read and develop. One basic aspect of programming style is the formatting of source code so that the program text aids the human reader.
  • A style convention specifies a particular manner of writing code: how to indent, how to name variables, etc. Different programming languages have their own style conventions; there are usually multiple alternative practices for any given language.
  • No matter which style you pick, you should apply it consistently so that you don’t put an extra burden on your reader. On the other hand, it can be okay to deviate from convention if there are reasons to do so in a particular context.
  • Links to the glossary: programming style, coding conventions; comment; to indent; identifier.

The Final Word

Any fool can write code that a computer can understand.
Good programmers write code that humans can understand.

—Martin Fowler

Feedback

Credits

Thousands of students have given feedback that has contributed to this ebook’s design. Thank you!

Weeks 1 to 13 of the ebook, including the assignments and weekly bulletins, have been written in Finnish and translated into English by Juha Sorva.

Weeks 14 to 20 are by Otto Seppälä. That part of the ebook isn’t available during the fall term, but we’ll publish it when it’s time.

The appendices (glossary, Scala reference, FAQ, etc.) are by Juha Sorva unless otherwise specified on the page.

The automatic assessment of the assignments has been developed by: (in alphabetical order) Riku Autio, Nikolas Drosdek, Joonatan Honkamaa, Jaakko Kantojärvi, Niklas Kröger, Teemu Lehtinen, Strasdosky Otewa, Timi Seppälä, Teemu Sirkiä, and Aleksi Vartiainen.

The illustrations at the top of each chapter, and the similar drawings elsewhere in the ebook, are the work of Christina Lassheikki.

The animations that detail the execution Scala programs have been designed by Juha Sorva and Teemu Sirkiä. Teemu Sirkiä and Riku Autio have done the technical implementation, relying on Teemu’s Jsvee and Kelmu toolkits.

The other diagrams and interactive presentations in the ebook are by Juha Sorva.

The O1Library software has been developed by Aleksi Lukkarinen and Juha Sorva. Several of its key components are built upon Aleksi’s SMCL library.

The pedagogy behind O1Library’s tools for simple graphical programming (such as Pic) is inspired by the textbooks How to Design Programs by Flatt, Felleisen, Findler, and Krishnamurthi and Picturing Programs by Stephen Bloch.

The course platform A+ has been created by Aalto’s LeTech research group and is largely developed by students. The current lead developer is Jaakko Kantojärvi; many other students of computer science and information networks are also active on the project.

For O1’s current teaching staff, please see Chapter 1.1.

Additional credits appear at the ends of some chapters.

a drop of ink
Posting submission...

Submission received.