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 ohjelmien koodissa englanninkielisiä nimiä kurssin alkupään johdantoesimerkkejä lukuunottamatta.

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


Chapter 3.5: Soda, Football, and Errors

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 churns out?

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).

../_images/person05.png

Example: VendingMachine

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.

Notice the packages

So far in O1, we’ve been carefree and written nearly all our code in the generic package o1. It is, however, better to split our work in separate packages, which is what we’ll do from now on.

You’ll notice multiple package as you browse the Miscellaneous module, for instance.

Initializing the state of a VendingMachine

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.

A few simple methods

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
  got
}
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:

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
  got
}
The first two methods have an effect on the object’s state. Even though the method bodies are short, we use curly brackets as we define these methods.
The next two short methods are effect-free and just return a value. We haven’t used curly brackets here (but it’s always okay to include them).
The fifth method has an effect on the object. This is why we have not only used curly brackets but also included a pair of round brackets as a parameter list, even though the method takes no parameters.

You can review the punctuation rules and conventions in O1’s style guide.

Implementing toString

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) "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 can 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 string literal.
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) "SOLD OUT" else s"$bottleCount bottles left"
  s"earned $earnings euros, inserted $insertedCash cents, $bottleStatus"
}

Implementing sellBottle

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) {
    -1
  } else if (!this.enoughMoneyInserted) {
    -1
  } else {
    this.earnedCash = this.earnedCash + this.bottlePrice
    this.bottleCount = this.bottleCount - 1
    val changeGiven = this.insertedCash - this.bottlePrice
    this.insertedCash = 0
    changeGiven
  }
}
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 combination.
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.

Is our implementation good?

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 twice.

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 improve sellBottle. You may wish to think back to this method during the upcoming chapters.

Scaladocs as Specifications in O1’s Programming Assignments

Scaladoc documentation will play an increasingly important role in O1, as many upcoming programming assignments use Scaladocs in two ways:

  1. 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”.
  2. 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.

Private variables in Scaladoc-based assignments

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 implemented class.

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).

Check your understanding

Which of the following claims are correct? Select all that apply. Make an informed guess if you need to and read the feedback.

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 = new VendingMachine(250, 10)machine: o1.soda.VendingMachine = earned 0.0 euros, inserted 0 cents, 10 bottles left
machine.earnedCash = 123456<console>:9: error: variable earnedCash in class VendingMachine cannot be accessed in o1.soda.VendingMachine
     machine.earnedCash = 123456
             ^

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.

Assignment: Spot the Errors

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.

Task description

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.)

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 the Scaladocs.

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 as intended.

Instructions and hints

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?

Step 1 of 12: Club

While the Football1 module or one of its files is selected, press F10 (or choose Build → Build Module 'Football1' in the menu). IntelliJ’n Messages tab pops up.

Initially, the tab shows a couple of errors in class Club, plus a warning about class Match. Don’t be fooled by this; there are errors in other parts of the program, too. It’s just that the error in class Club happens to be such that IntelliJ doesn’t even list the other problems before you fix Club. It’s not rare that one error in a program conceals other errors behind it.

Let’s begin with class Club. According to IntelliJ, there is an error in the class header and another at the very end of the file. Don’t take this too literally. 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. A single parsing error can make the computer see the entire program as invalid in numerous ways. Invalid brackets or other punctuation, for instance, may entirely throw off the automatic parser.

There is actually just a single, small error in class Club, albeit one that occurs twice on the same line. IntelliJ’s error message ':' expected but ',' found hints at the problem. It can be paraphrased as: “There was supposed to be a colon here, but there was a comma instead.” The comma between the constructor parameters in val name, val stadium is highlighted in red.

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 this ebook.

Some error messages are more opaque than that one. It may take quite a bit of brainwork and googling to work out what a message means. Practice makes perfect.

Step 2 of 12: isHigherScoringThan

Compile the code again (F10). The list of error messages updates. Now we have a flood of red in Match and (especially) the app object MatchTest.

Let’s deal with Match first. Double-click one of the two Error messages in the Messages tab to locate the corresponding line of code.

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 within the same method.

But what’s with that error message? IntelliJ’s complaint about the method call was: Int does not take parameters. At first glance, the message may seem weirder than the error itself, but it does make some sense if you know how to interpret it.

We know that totalGoals returns an integer. The method takes no parameters; this.totalGoals is an expression of type Int. That being so, the Scala toolkit interprets this.totalGoals(anotherMatch) as an attempt to “invoke an Int with anotherMatch as a parameter”, which makes no sense; hence the above message.

Step 3 of 12: goalDifference

Words of warning

Many programming tools, IntelliJ included, occasionally notify the programmer about questionable code with a warning (varoitus). In IntelliJ’s Messages tab, warnings look much like errors, except that they are marked with a yellow triangle warning.

A warning means that the code probably (but not certainly) has a problem worth addressing. By issuing a warning, the tool tells you the programmer: “Are you sure you really 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: procedure syntax is deprecated. The message suggests that you add the word Unit to the definition of goalDifference to make it explicit that the method returns Unit. The warning is timely but the suggestion isn’t.

Hover your mouse cursor over the name goalDifference. A description pops up, showing that the method now returns Unit. The suggestion in the warning message assumed that we want the method to return Unit, but we’d actually like an Int instead. The reason we now have Unit is familiar: a missing equals sign.

Fix the bug and recompile the module. The Match class seems to be in good shape now. Hold that sigh of relief, though.

Step 4 of 12: MatchTest and creating match objects

One of the remaining complaints concerns the command new Match(club2, club1) in the MatchTest object.

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 it like it’s supposed to be used.

Type mismatch is a common error message that, in simple cases, points us directly to the problem. Here, too, the message is pretty 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. Press F10 once again, and remember to keep doing that as you progress through the following steps.

Step 5 of 12: addAwayGoal

Now focus on the error messages that say: value addAwayGoal is not a member of o1.football1.Match. That is: there is no addAwayGoal method in class Match.

Eh? The method is defined right there; look for yourself.

Did you look carefully? And did you notice this question at end of the error message: did you mean AddAwayGoal?

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.

Step 6 of 12: homeCount and awayCount

Next up: variable awayCount in class Match cannot be accessed and the same story for homeCount.

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.

Step 7 of 12: totalGoals

A couple of the error messages involve the method call match1.totalGoals(). The complaint is familiar: Int 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 list.

Fix the problem.

Step 8 of 12: Creating Match objects, again

A line of code in MatchTest draws another protest from IntelliJ: not found: value Match. This means, roughly: “I can’t evaluate the expression Match.”

The message doesn’t do a great job of explaining what’s wrong here. But it does supply a clue: the Scala toolkit has attempted to interpret the individual word Match as the name of a variable or a method. Which isn’t what we want; we want to create a new Match object. The fix is very simple.

Step 9 of 12: isGoalless

Another error: type mismatch; found: AnyVal, 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 something called AnyVal.

Can you figure out or guess what’s wrong in isGoalless? Can you fix the problem`? Can you also greatly simplify the method?

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.

Step 10 of 12: location

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 the addAwayGoal case above, but this time the cause is different: this method is actually missing.

Implement location.

Step 11 of 12: Testing

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 us.

See below for hints.

Step 12 of 12: Fixes and toString

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.
    1. Make sure you read its entire Scaladoc.
    2. Make sure you included an override prefix.
    3. Revisit VendingMachine’s toString method above in this chapter.
    4. Take a look at the remainder of this chapter. You may have run into one of the if-related errors discussed below.
    5. Ask for help if you’re stuck.

A+ presents the exercise submission form here.

More Errors: Variables and Selection

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) {
    var result = first
  } else {
    var result = second
  }
  result
}
The code brings a compile-time error: not found: value result. Which sounds like the variable result is undefined on the last line of the function body.
But surely 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) first else second
  result
}

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) first else second

More Errors: Return Values and Selection

Why doesn’t this work?

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) number * number
  if (number <= 0) 0
}

This code explicitly 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) number * number
  if (number <= 0) 0
}experiment: (number: Int)AnyVal

The REPL accepts the function definition; this is a valid Scala function. But we run into trouble as soon as we use the returned number in a computation:

7 + experiment(10)7 + experiment(10)
  ^
<console>:12: error: overloaded method value + ...
cannot be applied to (AnyVal)

The error message means, roughly, “the plus operator isn’t defined for the data type AnyVal”. What is AnyVal?

Why it doesn’t work

The error message is a bit odd but it does have a point.

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.

def experiment(number: Int) = {
  if (number > 0) number * number
  if (number <= 0) 0
}
Our function first evaluates an if expression whose value is the square of the given number in case the number was positive. Otherwise this first if expression “has no value”; that is, it has only the contentless value Unit.
Then we evaluate the second if expression, which similarly yields either an Int value (of zero) or Unit.
The latter value becomes the return value of the entire function. In fact, the first if was completely inconsequential.

Since this (poorly defined) function returns either an Int or Unit depending on circumstances, the Scala toolkit infers its return type to be AnyVal, which you can think of as meaning “some kind of value”. Since addition has been defined for two numbers, not for a number and “some kind of value”, our attempt to evaluate 7 + experiment(10) fails.

A version that works

def experiment(number: Int) =
  if (number > 0) 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.

We’ll have more to say about AnyVal in due course (Chapter 7.3).

How about another solution?

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) number * number else if (number <= 0) 0

A couple of tips for error-hunting

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” and you have used an if.

The REPL displays the type of each expression that you enter. And in IntelliJ’s code editor, you can hover the mouse cursor above the code to view type information. Try it! (Hover the mouse over various parts of code and look at the types.)

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).

Summary of Key Points

  • In O1, many programming assignments come in the form of Scaladoc documents.
  • The error messages that programming tools produce may be cryptic, but with practice, you’ll learn to interpret them.
  • When you know that the branches of an if cover all the possible cases, make this clear to your programming toolkit with a final else branch that has no conditional.
  • Links to the glossary: documentation, Scaladoc; if; compile-time error, syntax error.

Feedback

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.

Credits

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

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, 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 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 library.

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 services. 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 was created by Nikolai Denissov, Olli Kiljunen, and Nikolas Drosdek with input from Juha Sorva, Otto Seppälä, Arto Hellas, and others.

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...