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.
Kieli vaihtuu A+:n sivujen yläreunan painikkeesta. Tai tästä: Vaihda suomeksi.
About This Page
Questions Answered: How are Scaladocs used in O1’s programming
assignments? How can I fix some common errors in my Scala code?
When will I learn to understand the error messages that IntelliJ
Topics: Additional practice on class definitions, the if
command, and other constructs. Error messages and hunting for
errors. Scaladocs as specifications.
What Will I Do? Read programs and program. You’ll need to marshal
multiple concepts and constructs to produce code that works.
Rough Estimate of Workload:? Three hours.
Points Available: A105.
Related Modules: Miscellaneous (new), Football1 (new).
Our next example involves virtual vending machines. We’ll create a class that purports
to control a simple machine that operates on coins and sells bottles of soda. (Disclaimer:
this is another intro-course example that cuts many corners.)
We’ll implement the class, VendingMachine, piece by piece, from a specification given
as a Scaladoc document (Chapter 3.2). This class will be somewhat more complex than the
ones we’ve examined so far and combines multiple themes from earlier chapters.
The example doesn’t have any new programming concepts or Scala constructs. If you feel
that you have a firm grasp on what we have covered so far, and if you aren’t wrong, you
could gloss over this example and skip ahead to the assignments that follow. (Or you may
wish to take up the additional challenge of implementing class VendingMachine on your
own before studying the solution below.)
Read the documentation NOW
Study the Scaladocs
of o1.soda.VendingMachine in module Miscellaneous.
Before reading further in this section, make sure you understand the
methods’ descriptions in the documentation.
The Miscellaneous module contains a working implementation for
VendingMachine, so you can already try using the class in the
REPL if you feel something was left unclear by the docs. We’ll
go through the implementation in detail below.
Consider, first, the constructor parameters and instance variables that we need for
implementing the class.
class VendingMachine(var bottlePrice: Int, private var bottleCount: Int):
private var earnedCash = 0
private var insertedCash = 0
As we create a vending machine, we pass in the price of a single
bottle as a constructor parameter. The machine needs to store this
information, so we also define the corresponding instance variable.
Our variable, bottlePrice, has the role of most-recent holder.
Since we let the user assign new values for the price, we use a
var (which is also specified in the documentation).
The other constructor parameter is the initial number of
bottles in the machine. This number, too, will change as bottles
are added and bought; a var will serve us as a gatherer.
This instance variable is meant only for the class’s internal use
and shall be private (Chapter 3.2). Note that you can also enter
the private modifier where you define an instance variable in
the class header.
The variable earnedCash records the amount of euro cents the
machine has earned by selling bottles since it was last emptied.
We need to keep a tally of these earnings in order to the
emptyCashbox method to work as specified. The variable is for
internal use only, so private. A newly created machine object
hasn’t yet earned a cent.
The variable insertedCash records the number of euro cents a
customer has inserted since the previous purchase. For example,
if the customer has inserted first 2 €, then 1 €, and no
bottle has been purchased since, the variable should have the
value 300. We need this variable for sellBottle to work as
specified. It, too, is private and initially zero.
Five of the methods are straightforward to implement given what you know from earlier chapters.
def addBottles(newBottles: Int) =
this.bottleCount = this.bottleCount + newBottles
def insertMoney(amount: Int) =
this.insertedCash = this.insertedCash + amount
def isSoldOut = this.bottleCount == 0
def enoughMoneyInserted = this.insertedCash >= this.bottlePrice
def emptyCashbox() =
val got = this.earnedCash
this.earnedCash = 0
addBottles and insertMoney simply use their parameters to
increase the values of the corresponding gatherer variables.
isSoldOut and enoughMoneyInserted each use a relational
operator to check for a particular situation and return the
result as a Boolean.
emptyCashbox resets the the machine’s earnings to zero and
returns the earnings that had accumulated before the reset. The
method uses a local temporary variable much like the account
object did in Chapter 2.2.
Perhaps it’s also worth our while to take another look at the same code while bearing in
mind Scala’s punctuation rules and style conventions:
The first two methods have an effect on the object’s state, so
we put their bodies separate lines even though the body is just
a single short line.
The next two methods are effect-free and just return a value.
Since they are that short, too, we are free to write them as
one-liners as shown here. These two methods don’t take any
parameter, and we don’t even give them a parameter list.
The fifth method is also parameterless, but it has an effect on
the object. This is why we’ve also included a pair of round brackets
as a parameter list despite the method taking zero parameters.
You can review these conventions in O1’s style guide.
Below is one way to implement the toString method using an if expression.
override def toString =
"earned " + this.earnedCash / 100.0 + " euros, " +
"inserted " + this.insertedCash + " cents, " +
(if this.isSoldOut then "SOLD OUT" else s"$bottleCount bottles left")
This method’s body is just a single, long expression that builds
up a string description from assorted pieces. You may split the
expression across multiple lines as shown; just make sure you
break each line after a plus operator, not in the middle of a
The last piece of the description depends on whether the machine
is out of soda or not. We use an if expression as a subexpression
within the method body.
We need the round brackets around the if expression to correctly
delimit the else branch (cf. the practice tasks near the beginning
of Chapter 3.4).
An alternative implementation
For comparison, here’s another implementation of toString. This version
defines a couple of local variables and embeds their values in the string.
override def toString =
val earnings = this.earnedCash / 100.0
val bottleStatus = if this.isSoldOut then "SOLD OUT" else s"$bottleCount bottles left"
s"earned $earnings euros, inserted $insertedCash cents, $bottleStatus"
One way of implementing sellBottle is shown below. This method should do the necessary
bookkeeping on money and bottles when a bottle is bought and return either the amount of
change given to the customer or a negative number to signal an unsuccessful purchase.
def sellBottle() =
if this.isSoldOut then
else if !this.enoughMoneyInserted then
this.earnedCash = this.earnedCash + this.bottlePrice
this.bottleCount = this.bottleCount - 1
val changeGiven = this.insertedCash - this.bottlePrice
this.insertedCash = 0
First we use isSoldOut to confim there is enough product. In
case we’re out of soda, we return -1.
In case we have a bottle to sell, we continue by checking whether
the customer has inserted enough money. Notice the else if
Reminder: the exclamation mark is the “not” operator, which flips
a Boolean value around. Here, we check to see if there is not
enough money. If so, we return -1.
We execute the commands that modify the object only in case both
checks “passed”. That being so, we add to the machine’s earnings,
subtract a bottle, determine change, reset the inserted cash, and
finally return the change.
Notice this, too: the value that a method returns depends on which
command is executed last. In code that branches out, this is not
necessarily the command that’s written last within the program text.
In this example, one of three different lines will be executed last,
depending on circumstances.
The above implementation of sellBottle meets the specification. But you might agree
that its sequence of ifs looks a bit unwieldy. The code is also not completely DRY
(i.e., free of redundancy) as the same command — returning -1 — unnecessarily features
We should also question whether it’s a good idea to communicate an unsuccessful purchase
by returning a negative number — even though signaling failure with a negative number
is a classic programmer’s trick. By doing so, we invite an error from any user of the method:
it’s easy to forget to check the sign of the returned number and instead handle
the minus one as if it was the amount of change received for a successful purchase.
Soon enough, you’ll learn other techniques that we could use to improve sellBottle. You
may wish to think back to this method during the upcoming chapters.
Scaladoc documentation will play an increasingly important role in O1, as many upcoming
programming assignments use Scaladocs in two ways:
In many assignments, you need to use one or more existing classes
that have been custom-made for O1 and documented as Scaladocs.
You’ll receive both the executable code and a description of its
interface: its “user manual”.
In many assignments, you’ll receive Scaladocs that describe
the interface of one or more classes whose implementation you
don’t have (at least not all of it). Your task will be to write
Scala code to match the given documentation. In other words, the
Scaladocs serve as a specification for your program, much as
with VendingMachine just now.
Recall from Chapter 3.2: private variables aren’t part of a class’s public interface
and therefore aren’t included in Scaladocs that describe how a programmer can use the
What that means for O1’s Scaladoc-based programming assignments is this: your classes
should have all the instance variables listed in the Scaladocs and those variables
should be public (like bottlePrice above). On the other hand, your class shouldn’t
have public instance variables that aren’t listed in the specification.
It’s not unusual that you’ll need additional instance variables for your class’s
internal use. Make those additional variables private (like bottleCount and
earnedCash in our example).
Don’t turn public vals into vars, either. Doing so allows the class’s users to
modify the variable and thereby changes the interface. If the docs ask for a val,
write a val. You can pick either val or var for private variables, of which
val is the better choice in most cases (Chapter 1.4).
Which of the following claims are correct? Select all that apply. Make an informed
guess if you need to and read the feedback.
A Scaladoc document for a class typically details the internal implementation of each of the class’s methods.
A Scaladoc document for a class typically describes the class’s interface.
A Scaladoc document for a class typically includes descriptions of the class’s private variables.
The private modifier’s primary purpose is improved security. We use it in order to prevent malicious “crackers” from accessing private data.
The private modifier’s primary purpose is to simplify the work of the programmers who use a class and to prevent mistakes.
In many of O1’s programming assignments, the student implements a class whose interface has been given.
So, it’s possible to access private data?
(You don’t need to know this in O1. Or often outside of O1,
either, for that matter.)
The private modifier prevents a variable (or method) from being
used outside of the class in the usual fashion. It marks the fact
that, under normal circumstances, it doesn’t make sense to access
that variable from the outside. Even so, as hinted in the feedback
to the above question, private isn’t an unsurmountable obstacle.
Consider class VendingMachine. One of its private methods is
earnedCash, whose value we adjust by calling public methods
on a VendingMachine object. The following attempt to access it
fails, as it should:
val machine = VendingMachine(250, 10)machine: o1.soda.VendingMachine = earned 0.0 euros, inserted 0 cents, 10 bottles left
machine.earnedCash = 123456-- Error:
|machine.earnedCash = 123456
|variable earnedCash cannot be accessed
But this works:
val accessToCurrentValue = machine.getClass.getDeclaredField("earnedCash")accessToCurrentValue: java.lang.reflect.Field = private int o1.soda.VendingMachine.earnedCash
accessToCurrentValue.setAccessible(true)accessToCurrentValue.set(machine, 123456)machine.emptyCashbox()res0: Int = 123456
This little trick bypassed the class’s intended interface and enabled
us to assign an arbitrary value to earnedCash. But this isn’t
something that you’ll do by accident.
Fetch the Football1 module. This program, which records the results of football (soccer)
matches, contains two classes named Match and Club as well as the app object MatchTest.
Class Match uses class Club: each football match features two competing clubs.
MatchTest is a simple application for testing the behavior of the two classes.
Read the Scaladocs that come with the module and browse the program code. (Reminder: you
can find an O1 module’s Scaladocs by opening the doc folder either in IntelliJ or through
the “Related Modules” links at the top of each chapter; further details in Chapter 3.2.)
Examining the code, you’ll eventually notice that:
It contains a number of syntax errors (“grammatical errors”;
Chapter 1.8) that prevent the classes from being used.
Some of the methods listed in the documentation are missing.
And that’s still not all, because:
There are bugs in functionality: some of the methods in class
Match are syntactically valid but don’t work as specified in
Your task is to:
fix the errors in classes Match and Club and fill in the
missing methods so that the classes conform to the specification;
adjust the test program MatchTest so that it works, that is,
so that it correctly uses class Match and its behavior matches
the comments embedded in its program code;
expand on the given test program so that it tests additional
features of the classes (as you see fit); and
use the test program to convince yourself that each method works
The errors in the given code resemble actual errors made by beginner programmers before
you. Learning to find and address these mistakes can help you avoid them in future
assignments where you program more freely.
Without guidance, this assignment is quite hard for a beginner. We strongly suggest that
you follow the guided ten-step approach below.
You did make sure to read the Scaladocs before you begin, right? And at least skimmed
the given code to get your bearings?
While the Football1 module or one of its files is selected, press F10 (or choose
Build → Build Module 'Football1' in the menu). IntelliJ’s Build tab pops
up. Initially, the tab lists various problems in Club, Match, and MatchTest.
There is actually just a single, small error in class Club, albeit one that occurs
twice on the same line. IntelliJ’s error message hints at the problem as it says ':'
expected but ',' found . That can be reworded as “There was supposed to be a colon
here, but there was a comma instead.”
You may double-click the error message to bring up the corresponding line in the editor.
The comma between the constructor parameters in val name, val stadium is highlighted in
val name, val stadium
Why should there be a colon there? What else is missing from that line? You can spot the
problem yourself. Or if not, compare the given class definition to the example classes in
Once you’re done editing, compile (build) your code again with F10.
The other error message from Club points and the class’s last line. The error on that
line is even smaller than the previous one.
The message says: misaligned end marker. Fix the indentation. (Since end markers are
optional, you could alternatively remove it.)
So far, these error messages have been fairly straightforward to interpret and have
correctly pointed at the locations of errors in our code. That is not always the case.
Some error messages are much more opaque than these, and it may take quite a bit of
brainwork and googling to work out what a message means. Practice makes perfect.
The Build tab reports just one error from class Match. Don’t be fooled by this;
in fact, that class is the part of this program with the most sorts of problems. It’s
just that the error in class Match happens to be such that IntelliJ doesn’t even
list any other problems before you fix the first one. It’s not rare that one error in
a program conceals other errors behind it.
The error message points at the line start starts with class Match and suggests that
a closing bracket might be missing: ')' expected, but ':' found. We’re lucky once again:
this message, too, is correct about the location and nature of the error.
Edit the closing bracket in. Compile your code again with F10. The list of
Match’s problems updates — and grows in length.
When a tool like IntelliJ attempts to parse a program, and something goes wrong (because
the program is invalid), one mistake can easily cause the entire parsing process to fail.
Invalid brackets or other punctuation errors may entirely throw off the automatic parser.
That’s what happened here, too: the missing bracket prevented the computer from processing
the rest of the class definition properly and listing some other errors. (The opposite
happens sometimes, too: a single parsing error makes the computer see the program as
invalid in a whole bunch of ways, and a small fix rids you of a slew of error messages.)
The Match class now gives us the message missing return type. Double-clicking the
message takes you to the goalDifference method.
That message is technically valid but not particularly informative in terms of what the
actual mistake is.
The function’s body is supposed to contain an expression (of type Int) that determines
the function’s return value. However, this function definition is missing a character
and, consequently, the function’s body does not get defined at all.
The fix is very simple: just add an equals sign to make the method return the value of
the expression that forms its body. (If you wish, you may also remove the line break and
write the whole method on a single line.)
Compile the code again with F10. The list of error messages updates; for Match,
we now have one error in red and a couple of warnings in yellow. Let’s look at the error
now and return to the warnings later. (MatchTest also spews a streams of errors, which
we’ll also deal with later.)
According to IntelliJ, the method call this.totalGoals(anotherMatch) is defective.
And indeed there is something wrong there. Can you tell what it is? Fix this error and
another similar one on the same line. The error message method totalGoals in class Match
does not take parameters is on point.
Fix the bug and recompile the module. The Match class seems to be in good shape now,
apart from the warnings. Hold that sigh of relief, though.
Words of warning
Many programming tools, IntelliJ included, occasionally notify the
programmer about questionable code with a warning (varoitus).
In IntelliJ’s Build tab, warnings look much like errors,
except that they are marked with a yellow triangle .
A warning means that the code probably (but not certainly) has a
problem worth addressing. The tool tells the programmer: “Are you
sure you want to be doing that?”
When IntelliJ warns you about something, it’s often right in that
something in the program should be changed. The automatic message
may be less insightful as to what should be changed, though.
A good rule of thumb is to take your warning messages like you take
your error messages: seriously.
IntelliJ emits a warning about class Match — more specifically, about the isGoalless
method in that class. The warning says that a pure expression does nothing in statement
position and suggests that maybe you’re missing some parentheses there.
The warning is timely in that the method indeed does have a problem. The warning text is
misleading, however, and the suggestion about parentheses is completely off the mark.
Perhaps you already spotted what’s wrong isGoalless. But let’s not fix that method just
yet, because it’s instructive to see the errors that the problem causes elsewhere in the
program. We’ll get to that a bit later. For now, let the warnings be and proceed to the
We have a flood of red in MatchTest. Most of the messages say illegal start of
toplevel definition. The errors seem to arise from various lines that call functions
and that reside within the MatchTest object.
Those messages don’t do a great job of explaining what’s wrong here, nor do they directly
point at the problematic line of code. But they do supply a clue about how the computer
has attempted to parse the program.
We can interpret the messages as saying “A line of code at the top level can’t start like
that”, where “top level” refers to code that isn’t placed within any function, singleton
object, or class.
That complaint sounds odd — surely those error lines follow the header object MatchTest
and are thus located within the MatchTest object, aren’t they? So why does IntelliJ
claim that the lines are inappropriately at the “top level”?
Once again, we have an issue of punctuation. Look at the end of the line that starts
object MatchTest. There’s a problem there, as a consequence of which the entire object’s
definition consists of just that single line. None of the code that follows counts as
part of MatchTest’s definition (despite the indentations). Add the missing character
Many of them went away, but some illegal start error remain to haunt us. The first of
them points at a particular println call.
A close look at the code tells us that the line is inappropriately indented, as is the
next one. They indeed are at the “top level” where they don’t belong. Fix them.
Press F10 once again, and remember to keep doing that as you progress through the
One of the remaining complaints concerns the command Match(club2, club1) in the
Yet that command seems just fine. It is just fine.
This is a good example of how an error message doesn’t always point to the spot where the
actual error is. What we have here is a message saying that MatchTest doesn’t work, and
indeed it doesn’t, but the reason is that Match has been incorrectly defined, whereas
MatchTest attempts to use Match like it’s supposed to be used.
Note that the full error message consists of more than one line. You can view it in the
Build tab, next to the list of errors, once you’ve selected the error in the list.
This is a type mismatch error. Such a message states that a certain data type was
expected (or “required”) in a particular context but data of another type was found
instead. In simple cases, these messages point us directly to the problem. Here, too,
the message is reasonably clear as to what caused it. Read the message, then compare the
indicated line, the Scaladocs of class Match, and the given implementation of Match.
Fix the error.
Now focus on the error messages that say: value addHomeGoal is not a member of
o1.football1.Match. That is: there is no addHomeGoal method in class Match.
Eh? The method is defined right there; look for yourself.
Did you look carefully? And did you notice the question at end of the error message:
did you mean AddHomeGoal?
When you get a message like this, the first thing to do is check your spelling.
There may be a typo in the definition or in the code that uses the definition.
Next up: variable awayCount in class Match cannot be accessed and the same story for
These error messages are fairly apt. They tell us that those variables in Match
cannot be accessed from class MatchTest.
If you didn’t already notice the variables homeCount and awayCount in class Match,
and the methods homeGoals and awayGoals, notice them now.
What is the problem? Is the error in Match or MatchTest?
Fix the problem.
One of the error messages involves the method call match1.totalGoals(). The complaint is
familiar (from above): method totalGoals does not take parameters. The reason is familiar,
too, even though here we don’t attempt to pass any actual parameters, just an empty parameter
Uhh, what’s this? Value isHomeWin is not a member of o1.football1.Match. And the same for
But surely those methods exist in class Match!? Their names are correctly spelled and all
Yes, those definitions are there in Match’s code, but a small but crucial mistake prevents
them from being available as methods on Match objects. The tiny example below will lead you
to the solution.
Say we want to define a class with three methods like this:
def action1(num: Int) =
def action2 = 1 + 1
def action3 = 2 + 2
But maybe we make a careless mistake and instead write this:
def action1(num: Int) =
def action2 = 1 + 1
def action3 = 2 + 2
That second class definition means the same as this next one, which has an
explicit end marker:
def action1(num: Int) =
def action2 = 1 + 1
def action3 = 2 + 2
That is, what we have here is action2 and action3 defined inside the method action1.
They become local functions within action1 rather than methods on class MyClass.
(This is not at all what we intended here. Local functions can be quite useful elsewhere,
though, as you’ll see later in O1.)
Fix the methods isHomeWin and isAwayWin in class Match. Indentations are important!
Another error: Found: Unit Required: Boolean. The message points to the isGoalless
calls in MatchTest.
It’s clear that we need Boolean expressions for the ifs in MatchTest. But somehow,
isGoalless appears to produce not a Boolean but Unit.
Can you figure out or guess what’s wrong in isGoalless? Can you fix the problem? Can
you also greatly simplify the method? Sometimes, all it takes to fix a bug is to remove
If you have trouble figuring out what’s wrong, take a look at the section More Errors:
Return Values and Selection below. It discusses this specific sort of error. Do the
mini-assignment at the end, too. (And remember the above hint: it’s possible to write
a body for isGoalless that is extremely simple but works.)
Fixing this method also eliminates the warning message that we spotted earlier.
The remaining compile-time errors from MatchTest also arise from defects in Match.
The message value location is not a member of o1.football1.Match tells us that we’re
missing a location method or variable in Match. The symptom is similar to ones that
we got for some other methods above, but this time the cause is different: this method
is actually missing completely.
The program should be ready to run. Launch MatchTest. Consider what it should print
out and see what it actually prints out.
You’ll notice that some of the output is fine, but all is not well. Class Match still
doesn’t quite meet the specification even though IntelliJ can’t spot any more errors for
See below for hints.
Fix class Match: find and edit the flawed method and add the
missing toString method.
Instructions and hints:
As you search for the remaining logical error, edit MatchTest
as you see fit.
A reminder (for the last time): you should click the method
names in the Scaladocs to see the full descriptions.
If you have trouble implementing toString, try the following.
Make sure you read its entire Scaladoc.
Make sure you included an override
Revisit VendingMachine’s toString
method above in this chapter.
Take a look at the remainder of this
chapter. You may have run into one of
the if-related errors discussed below.
Ask for help if you’re stuck.
A+ presents the exercise submission form here.
Let’s look at some more code that doesn’t work. The remaining examples in this chapter
can improve your understanding of if expressions and other Scala constructs. They may
also help you avoid some common mistakes.
Below is a function that resembles the library function min. This function was written
by an earlier O1 student, who was puzzled by the error message that it produces. Many
beginners have made a similar mistake.
def returnSmaller(first: Int, second: Int) =
if first < second then
var result = first
var result = second
The code brings a compile-time error: not found: result.
That sounds like the variable result is undefined on the
last line of the function body.
But clearly result is defined. Twice no less.
The problem is this: result is defined only within the branches of the selection
command. Each of these two definitions covers only that branch, and neither of the
two variables can be used outside of the if.
If we want to access the variable after the selection command, we need to define it
outside the command. This works, for example:
def returnSmaller(first: Int, second: Int) =
val result = if first < second then first else second
This example has brought us in touch with the fact that each variable has a scope in
which it is available (käyttöalue). That’s something we’ll discuss further in Chapter 5.6.
Just to be clear: in the previous example, it isn’t necessary to store the result in a
variable. The simpler implementation below also works.
def smaller(first: Int, second: Int) = if first < second then first else second
Suppose that we wish to write a function that takes an Int and returns an Int. In case
the given number is positive, the function returns the square of that number. In case the given
number is negative, the function returns zero instead.
Here’s an attempted solution:
def experiment(number: Int) =
if number > 0 then number * number
if number <= 0 then 0
This code clearly articulates each of the two cases with a separate if. However, it
also contains a common beginner’s mistake. Let’s try it in the REPL:
def experiment(number: Int) =
if number > 0 then number * number
if number <= 0 then 0def experiment(number: Int): Unit
-- Potential Issue Warning:
if number <= 0 then 0
This is, in principle, a valid Scala function. The REPL accepts
it and indicates that the function got defined, but...
... warns that something could be amiss here.
It looks as if our function has a return type of Unit even
though we wanted it to return an Int.
And we run into trouble as soon as we use the function:
experiment(10)7 + experiment(10)-- Type Error:
7 + experiment(10)
None of the overloaded alternatives of method + in class Int ... match arguments (Unit)
We don’t get a number as a return value. And if we try to use the function as part of
a computation, we get an error message that means, in essence, “the plus operator isn’t
defined for a combination of Int + Unit”. Our function clearly does return just
Unit. What’s going on?
Let’s take a good look at our code and bear in mind that the function’s return value is
the value of the expression that is evaluated last.
Our experimental function contains two if expressions, which
are completely separate from each other. The second one comes
after the first one. Neither if expression is in the other’s
else branch or connected to the other expression in any way.
The function first evaluates an if expression whose value
is supposed to be the square of the given number in case the
number was positive. This expression has no else branch and
it completely fails to define what the value is supposed to be
Next (and completely independently of what happened on the
preceding line), the second if is evaluated. This expression,
too, specifies which value is produced by one of the branches
(i.e., zero) but completely fails to specify what happens
otherwise — and this second line has no clue about what
happened on the previous one, and so has no way of excluding
the possibility of a positive number.
The latter value becomes the return value of the entire function.
In fact, the first if was completely inconsequential.
Since this (poorly defined) function’s returns something that’s either an Int or
something unspecified, the Scala toolkit works out that the type is Unit — i.e.,
Our else-less expression if number <= 0 then 0 is effectively a
shorthand for this expression:
if number <= 0 then 0
if number <= 0
The empty brackets stand for Unit.
def experiment(number: Int) =
if number > 0 then number * number else 0
Now the last expression to be evaluated is this single
if expression whose value is of type Int no matter
which branch is chosen.
Consider one more function implementation. Again, the intention is that the function’s
return type is Int and the function returns either the square of the given number
or zero. Does this implementation work? Study the code and experiment in the REPL if
you want. Then submit your answer and remember to read the feedback.
def experiment(number: Int) =
if number > 0 then number * number else if number <= 0 then 0
Yes, that works.
No, that does not work.
When you get a puzzling error message, check the data types of the expressions and return
values in your program. This advice is generally sound, and it’s especially pertinent
when the message contains the word “Any” or “Unit” and you’ve used an if.
Another trick: in some cases, you’ll get more informative error messages if you annotate
your function with an explicit return type (Chapter 1.8), as shown below:
def experiment(number: Int): Int = // etc.
Feel free to annotate every function’s return type like this, if you want. These voluntary
annotations can clarify program code and reduce the likelihood of future errors. Many Scala
programmers add a type annotation to every public method (which is however not required of
you in O1).
In O1, many programming assignments come in the form of Scaladoc
The error messages that programming tools produce may be
cryptic, but with practice, you’ll learn to interpret them.
When you use an (effect-free) if expression to select between
values, make sure to have a final else branch with no conditional
so that some value gets picked under any circumstance.
Links to the glossary: documentation, Scaladoc; if;
compile-time error, syntax error.
Please note that this section must be completed individually.
Even if you worked on this chapter with a pair, each of you should submit the form separately.
Time spent: (*) Required
Please estimate the total number of minutes you spent on this chapter (reading, assignments,
etc.). You don’t have to be exact, but if you can produce an estimate to within 15 minutes or
half an hour, that would be great.
“I feel that I have understood the most important things in this chapter.” (*) Required
I’m unable to answer or don’t want to comment.
Written comment or question:
You aren’t required to give written feedback. Nevertheless, please
do ask something, give feedback, or reflect on your learning!
(However, the right place to ask urgent questions about programs
that you’re currently working on isn’t this form but the lab sessions
or Piazza. We can’t guarantee that anyone will even see anything
you type here before the weekly deadline.)
Thousands of students have given feedback and so contributed to this ebook’s design.
The ebook’s chapters, programming assignments, and weekly bulletins have been written in
Finnish and translated into English by Juha Sorva.
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, Antti Immonen, Jaakko Kantojärvi, Niklas
Kröger, Kalle Laitinen, Teemu Lehtinen, Jaakko Nakaza, Strasdosky Otewa, Timi Seppälä,
Teemu Sirkiä, Anna Valldeoriola Cardó, 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 did 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
The pedagogy of using O1Library 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+ was originally created at Aalto’s LeTech
research group as a student project. The open-source project
is now shepherded by the Computer Science department’s edu-tech team and hosted by the department’s IT
Markku Riekkinen is the current lead developer; dozens of Aalto students and others have also contributed.
The A+ Courses plugin,
which supports A+ and O1 in IntelliJ IDEA, is another open-source project. It has been designed and
implemented by various students
in collaboration with O1’s teachers.
For O1’s current teaching staff, please see Chapter 1.1.
Additional credits appear at the ends of some chapters.
As we create a vending machine, we pass in the price of a single bottle as a constructor parameter. The machine needs to store this information, so we also define the corresponding instance variable. Our variable,
bottlePrice, has the role of most-recent holder. Since we let the user assign new values for the price, we use a
var(which is also specified in the documentation).