This course has already ended.

The latest instance of the course can be found at: O1: 2024

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.


Chapter 9.1: Robots and Conditional Looping

About This Page

Questions Answered: How can I repeat sequence of a commands if I can’t find a higher-order method that’s sufficiently convenient or efficient for my needs? I’ve heard programmers talk about something called a while loop — what are they, and does Scala have them? How about creating different sorts of robots?

Topics: A classic from the imperative programmer’s toolkit: while loops. A class hierarchy for robots. We’ll say a bit more about lazy-lists, too.

What Will I Do? First read, then program.

Rough Estimate of Workload:? This is one of the most time-consuming chapters in O1. Reading the text and doing the next two parts of the Robots assignment will probably take about two or three hours. The last parts of the assignment might take another four or five hours.

Points Available: A15 + B50 + C85.

Related Modules: Robots. Plus some mini-examples in WhileLoops (new).

../_images/person02.png

Introduction

Recap from 6.3 and 7.1: When solving a programming problem, you may be able to find a tool at a high level of abstraction that provides a simple solution for just what you need. If you don’t, you can build a solution using lower-level tools. Those lower-level tools may not be quite as convenient to use but they are applicable to a wider range of situations; any higher-level tools you have at your disposal have also been built from lower-level pieces. Occasionally, it makes sense to deliberately adopt lower-level tools to optimize efficiency.

An Example Program

Consider a toy example: We’re writing an interactive program that prompts the user for their name. We’d like the program to check that the user actually enters a string that contains at least one character; the program should keep re-prompting the user until it receives a non-empty string.

The program should work in the text console as illustrated below. In this example run, the user first just hits Enter twice, then actually inputs their name:

Enter your name (at least one character, please):
The name is 0 characters long.
Enter your name (at least one character, please):
The name is 0 characters long.
Enter your name (at least one character, please): Juha
The name is 4 characters long.
OK. Your name is Juha. Hello!

In Chapter 7.2, we approached problems like this by thinking about a lazy-list of inputs and the operations that we applied to the list elements. Alternatively, we may think of the program in imperative terms: as a sequence of commands that adjust the program’s state step by step. Let’s formulate such a solution, first as pseudocode:

var name = ""

Check whether name equals the empty string. If so, do the following things; otherwise skip past them:
    name = readLine("Enter your name (at least one character, please): ")
    val len = name.length
    println(s"The name is $len character${if name.length != 1 then "s" else ""} long.")
    Go back to the step that checks whether name is empty.

println(s"OK. Your name is $name. Hello!")

Our pseudocode resembles an if statement in that it checks a condition — is the name empty? — and uses the result to decide where to proceed in the program. The main difference is that this code is potentially executed multiple times: we keep going back as long as the condition keeps being met.

On the other hand, this program resembles a for loop in that it too involves repetition, a loop. However, this loop isn’t tied to a collection like the for loops you’ve seen. Instead, it’s formed by repeatedly checking a particular condition.

The while Loop

Here is a Scala implementation for our pseudocode. You can also find this program inside the WhileLoops module.

var name = ""
while name.isEmpty do
  name = readLine("Enter your name (at least one character, please): ")
  val len = name.length
  println(s"The name is $len character${if name.length != 1 then "s" else ""} long.")
end while
println(s"OK. Your name is $name. Hello!")

This is a while loop. We also use the do keyword that you already know from for loops.

Between while and do, we write a Boolean expression. (This is similar to how we use if and then.) This condition is evaluated before each execution of the loop body below.

The end marker at the bottom of the loop is optional. There’s also no need to write a “go back to the top” command (such the one we had in our pseudocode above). Whenever any while loop reaches the end of the loop body, it jumps back to check the looping condition.

The loop body is executed after the conditional expression has been checked and evaluated to true. This may happen multiple times. In this example, the loop body executes each time name is checked and holds an empty string. We indent the loop body in the usual style.

The last line in our example isn’t part of the loop. It’s executed only after the loop exits, which happens after the condition has been checked and found to be false.

Here’s a generic outline for a while loop:

(Up here, you might have some commands that precede the loop and are executed just once.)

while condition do
  One or more commands that are executed zero or more times,
  checking the condition before each iteration. If the condition
  is true, these commands are executed once more before rechecking.
end while   // optional line

(After the condition evaluates to false the program advances to any commands that follow the loop.)

Another example of a while loop

Study the animation below and predict the program’s behavior when prompted.

What does “while” mean exactly?

Beginners are occasionally confused by how Scala and many other programming languages use the English word while. Consider the program above. Since “while” means “as long as”, one might easily think that as soon as number reaches 13 — which isn’t less than 10 — the loop exits and we proceed to the code that follows. However, the condition is only checked after each complete execution of the loop body, and so the program prints 13 twice.

For the same reason, our first program reports “The name is X characters long.” also after the user has entered the final, non-empty input.

Practice reading while loops

Consider what happens while the program below runs. Which values are stored in result at each step?

var result = "TRO"
while result.length < 10 do
  result += "LO" * (result.length / 2)

In the field below, please list all the strings that are stored in result during the program run. Write each string on its own line, in order. Don’t forget the final value!

Compare these two programs:

def exampleA(limit: Int) =
  var number = 1
  var square = 1
  println(square)
  number += 1
  square = number * number
  while square <= limit do
    println(square)
    number += 1
    square = number * number
def exampleB(limit: Int) =
  var number = 1
  var square = 1
  while square <= limit do
    println(square)
    number += 1
    square = number * number

Which values of limit cause the two programs to generate different output?

Some Loop-Writing Advice

When you write a loop, take care. If you break even one of the “golden rules of looping” listed below, you’ll have a buggy program on your hands.

val word = "llama"
var index = 0
while index < word.length do
  println("Letter: " + word(index))
  index += 1

#1 Initialize: Set up the program’s initial state as appropriate before starting the loop. What this often means in practice is that you’ll need to initialize one or more vars.

#2 Terminate: Make sure your loop is controlled by an appropriate conditional expression. In this example, we cap the value of the index variable; once we reach the limit, it’s time to stop.

#3 Advance the Loop: Your loop needs to modify the program’s state so that the loop will eventually terminate. Here, we increment the index variable so that it eventually reaches the limit we’ve set.

#4 Actually Do Stuff: Of course, you’ll need to include one or more commands that cause whichever effect your loop is designed to bring about. This toy loop’s only purpose is to print out some letters.

What happens if you overlook one of these “rules” depends on the specific loop. A fairly typical outcome is a so-called infinite loop: the computer repeats the same commands “forever”, that is, until it runs out of resources or the program run is externally interrupted.

Consider what would happen if we had forgotten the line that increments index from the above program. Which of the following best describes that scenario?

How about this program?

val word = "llama"
var index = 0
var result = ""
while index < word.length do
  result += word(index).toString * (result.length + 1)
println(result)

When does an “infinite” loop stop? How can one stop it?

The alternatives are more or less the same as those in a boxing match:

  • Concession: The user can interrupt the program. How that is done depends on the environment where the program is running. In IntelliJ, you can click the red Stop button. Many command-line environments use the keyboard shortcut Ctrl+C.

  • Technical knockout: If the program keeps consuming more and more memory, it will eventually crash with an error once that resource is depleted.

  • Disqualification: If you submit such a program in A+, the system will interrupt it after a while by externally terminating the process that executes your program.

  • Knockout: Power off.

Of course, the main thing to do is to prevent such problems, not to react to them.

Programmer Jim was heading to the store to pick up groceries.
As he was leaving the house his wife said: “While you are there, buy some milk.”
Jim never came back.

—thanks to the O1 student who shared this cautionary tale

A Couple of Voluntary Exercises

Loop-writing practice

In Chapter 7.2, we wrote this little program:

def report(input: String) = "The input is " + input.length + " characters long."
def inputs = LazyList.continually( readLine("Enter some text: ") )
inputs.takeWhile( _ != "please" ).map(report).foreach(println)

Rewrite the program to use while loop instead of LazyList. The program’s behavior should be the same as before. Write your code in task1.scala in the WhileLoops module.

A+ presents the exercise submission form here.

More practice

In task2.scala, write a program that works in the text console as illustrated in these example runs:

I will compute the squares of positive integers and discard other numbers.
To stop, just hit Enter.
Please enter the first number: 10
Its square is: 100
Another number: 0
Another number: -1
Another number: 20
Its square is: 400
Another number: 30
Its square is: 900
Another number: 0
Another number: 40
Its square is: 1600
Another number:
Done.
Number of discarded inputs: 3
I will compute the squares of positive integers and discard other numbers.
To stop, just hit Enter.
Please enter the first number: 0
Another number: 0
Another number: 0
Another number: 0
Another number:
Done.
Number of discarded inputs: 4

Even the first input may be empty:

I will compute the squares of positive integers and discard other numbers.
To stop, just hit Enter.
Please enter the first number:
Done.
Number of discarded inputs: 0

A+ presents the exercise submission form here.

while vs. Higher-Level Tools

Comparing solutions

These two snippets do essentially the same thing: multiply some integers by two and find the first one that fulfills a particular condition:

val result = LazyList.from(0).map( _ * 2 ).dropWhile( _ <= 20 ).head
val result =
  var number = 0
  var doubled = 0
  while doubled <= 20 do
    number += 1
    doubled = number * 2
  end while
  doubled
end result

In the LazyList solution, the function we pass to dropWhile has the same purpose as the conditional expression in the while loop.

Here’s a toy function that we’ll need for our next example:

def examine(number: Int): Boolean =
  println(s"I’m examining the number $number. Is it over 90?")
  number > 90

The next two snippets generate some random numbers until they happen upon a sufficiently large random number:

LazyList.continually( Random.nextInt(100) ).map(examine).find( _ == true )
var isBig = false
while !isBig do
  isBig = examine(Random.nextInt(100))
end while

In this solution, the find call serves the same purpose as the loop’s conditional: it governs the number of repetitions.

As generate random numbers in the Int list, we'll call examine on each number. This yields a lazy-list of Booleans.

We do this until examine returns true on an element and find therefore stops examining the lazy-list further. Once that happens, no more random numbers or Boolean values are generated.

We could have alternatively used some other method that forces the lazy-list to generate elements until true. Calling contains(true) also works, for instance.

If we were to remove the final method call .find( _ == true ) from the above program, how would the program behave?

Which tools should I choose?

It should be clear by now that you can use while loops for the same purposes as the higher-order methods that you’ve seen earlier. Often that isn’t the best idea, but sometimes it does pay off.

By choosing to use the higher-order methods on collections, you emphasize the data that your program works on and the operations on that data. When you use these methods, you leave the details of step-by-step execution for library methods to deal with and focus on expressing the program’s purpose. Which is nice.

By choosing to use while, you instead emphasize the step-by-step execution of commands. This command brings you a little bit closer to the low-level sequential execution that takes place within the computer system as it runs your programs. When you use these loops, you assume direct control of the program’s flow of execution and specify the sequential steps of your algorithm in detail.

For many purposes, while loops are unnecessarily detailed. Generally, if you opt for higher-order methods instead, you’ll have less work to do, you’ll write code that is more readable, and your program is less likely to contain errors. That being said, there are reasons to use while loops sometimes. For instance:

  • Perhaps you’re implementing an algorithm that relies on modifying the program’s state step by step. Due to the nature of the algorithm, it can be natural to write it down as a sequence of consecutive steps. For instance, some programs that engage the user in dialogue in the text console probably fall in this category. The robot assignments below in this chapter could be argued to fit this description too.

  • Or perhaps you’re working on an application that needs to be highly efficient (i.e., it needs to run fast). Perhaps you’ve studied your code carefully and identified a subprogram that requires optimization. Depending on circumstances, it might be beneficial to write a loop that painstakingly details the exact operations in the subprogram rather than leaving those minutiae to library methods.

Conditional loops such as while are available in many programming languages and they are used widely. As you continue studying programming, you will keep running into these constructs. In fact, they are probably used too much by many programmers. Sometimes, people use them because the programming language affords them no alternatives; sometimes, people use them because of the surrounding programming culture or because of historical inertia; sometimes, people use them because they are unaware of better alternatives.

You should know these loops. But don’t think of them as the primary or only means to implement repetition in a program. Higher-order methods are convenient, elegant, and efficient enough for most purposes, and there are other alternatives too.

Loops as first-class citizens

Chapter 6.1 mentioned the expression “first-class functions”, which refers to the notion that a programming language treats functions like it treats other values: functions can be assigned to variables, passed as parameters, returned by functions, etc.; they are first-class citizens of the language,

Chapter 7.2 brought up lazy-lists, which enabled us to create collections of indeterminate length and repeat operations until a given condition was fulfilled. That is, we could use lazy-lists for the same sorts of things that we’ve used loops for in this chapter. On the other hand, a lazy-list — unlike a loop — can be treated as data: you can invoke methods such as map on a list to produce a different list, or you can call find, contains, or exists to iterate over a part of a list. This is why some people call lazy-lists “first-class loops”.

Lazy-lists are best suited for working on immutable data with effect-free functions. When working on mutable state with effectful functions, you need to be careful not to obscure the step-by-step flow of the program too badly; in such situations, a while loop may be more readable than a lazy-list.

What about for loops?

The code of a for loop defines the loop’s “shape” simply and implicitly: after each iteration of the loop body, the loop advances towards termination by plucking the next element from the collection. The implicit condition for continuing the loop is “as long as there are more elements to process”.

for loops thus operate on a higher level of abstraction than the more explicit while loops. Scala’s for loop is a flavor of syntactic sugar, a different notation for a higher-order method call.

Robots That Change Location

You’ve done the first four parts of the Robots assignment. Now’s the time for the remaining five.

Robots, Part 5 of 9: Nosebot

Implement a type of mobile robots as class Nosebot:

  1. Define the constructor parameters and the rest of the class header.

  2. Write the simple mayAdvance method. (Remember to override.)

  3. Two movement methods are missing: moveBody and attemptMove. Start with the latter and use it as you implement moveBody. Pay attention to what attemptMove returns; that’s useful.

    A lazy-list or a loop?

    You could implement moveBody with a loop. Alternatively, you could use a lazy-list. Can you come up with both solutions? (You don’t strictly need to, but do try.)

    A hint for the lazy-list solution: you can, for example, use a combination of map and find similar to the one in the random-numbers example above.

  4. Try creating some nosebots in the app’s GUI and see if they work right.

If your bot moves at double speed, check this out

In this assignment, quite a number of students end up with code that moves the nosebot forward twice, which is too fast. If that happens to you, and you can’t figure out why, see the hint below for a likely explanation.

Show the hintHide the hint

What does this code print out?

def test(i: Int): Boolean =
  println("hello")
  i > 0

if test(10) then
  test(10)

Answer: it prints "hello" twice. The test function first gets called in the if’s condition, which causes the first "hello" to be printed and true to be returned. Because of that return value, the same function then gets called again and another "hello" to appear.

A very similar thing may have happened to you when you’ve called attemptMove.

  1. Notice how the program’s design made it very easy to add a new type of robot in the simulator. Basically, the only thing you needed to do was implement the algorithm that nosebots use for moving.

  2. Submit your solution before moving on to the next part.

A+ presents the exercise submission form here.

Robots, Part 6 of 9: collisions

Spinbots and Nosebots never collide with anything during their own turn but other sorts of robots, such as the ones you’re about to implement in Part 8, may. Before that, though, you’ll need to set up a few things so that Square’s subtypes support collisions.

Wall and Floor are defined in the same file as their supertype Square: Square.scala. Improve them as follows.

  1. The Wall singleton’s addRobot method doesn’t do anything yet, apart from returning a value that indicates that the arriving robot did not fit into the same square with the wall. Edit this method so that it breaks any robot attempting to enter a wall square.

  2. Also edit the addRobot method in class Floor so that it meets the specification. The method should attend to collisions between robots.

Robots, Part 7 of 9: Staggerbot

Implement Staggerbot.

You’ll need a random-number generator (Chapter 3.6) and you’ll need to use it exactly as specified in the Scaladocs. Create a single generator per Staggerbot object, and pick a random number when — and only when — the bot needs another a random direction. (If your implementation deviates from the Scaladoc, your code will produce random numbers that differ from what A+ expects, and you won’t score points.)

Instructions and hints:

  • You’re allowed to write private methods, and we recommend that you do. For instance, you could write a separate method for picking a random direction.

  • The moveTowards method returns a useful value.

  • If you fail to score points even though your bot’s movements appear random, you’ve probably not generated the random numbers exactly according to specification. Here are some things to check:

    • When you create a random-number generator, do you pass in the appropriate seed?

    • Are you creating precisely one generator per bot? You aren’t creating a new generator every time moveBody is invoked, right? Or every time a new random number is generated?

    • Are you generating only those numbers that are actually needed? That is, one for the bot’s direction of movement, and maybe — only if the movement succeeds! — another for the bot’s spinning direction?

    • Did you generate a number in the right interval. For example, nextInt(10) gives you a number between 0 and 9, inclusive.

A+ presents the exercise submission form here.

You may find it helpful to add private methods during the following steps, too.

Robots, Part 8 of 9: Lovebot

Implement Lovebot.

A+ presents the exercise submission form here.

Robots, Part 9 of 9: Psychobot

Implement Psychobot.

You again have a choice between a loop and/or methods on lazy-lists. Can you implement the class in different ways?

You may find the methods in GridPos useful; check the Scaladocs.

A+ presents the exercise submission form here.

Chapter Summary

  • Many programming languages have a construct known as a while loop; many, many programs contain such loops. These loops repeat a command or sequence of commands as long as a specific condition continues to be met.

    • When writing these loops, you must pay particular attention to initializing the loop, setting an appropriate condition for continuing, and advancing the program’s state so that the loop will eventually terminate.

  • for loops and higher-order methods are often efficient enough and quite a bit more convenient than while loops.

  • Links to the glossary: loop, while loop, iteration; lazy-list; level of abstraction.

Hey, What About break and continue? And return? And Other Types of Loops?

Some readers who have earlier exposure to other programming languages will be familiar with additional commands that sometimes appear in loops. If you’re one of those readers, you may be wondering if Scala also has those commands.

See below for answers, which are educational for complete beginners, too.

Loop-breaking commands

Various programming languages have commands for exiting a loop body either by terminating the loop altogether (break) or by jumping back to the top for a new iteration (continue).

When programming in Scala, such commands are seldom used. You can handle practically any scenario more elegantly by choosing a different approach. However, there is a break command of sorts available in the Scala API; see elsewhere for more information. Scala doesn’t provide a continue command, since that command is so very rarely useful in a well-designed Scala program.

Returning a value from a loop

Various programming languages have a command that explicitly instructs the computer to immediately terminate the ongoing function call and return a value. This command is usually named return. Programmers may use it to interrupt a function call during a loop, terminating the loop at once along with the rest of the function.

Scala, too, has the return keyword, although it is rather rarely used. In most cases, it’s possible to find a better solution without it, although this is to an extent a matter of taste.

A simple example of return is shown below. This function loops through a vector and returns the first non-empty string. (That is, the following code does essentially the same as vector.find( _.nonEmpty ), although this actually isn’t quite as efficient on Vectors as that library method.)

def firstNonEmpty(vector: Vector[String]): Option[String] =
  var index = 0
  while index < vector.size do
    val element = vector(index)
    if element.nonEmpty then
      return Some(element)  // Found it. Terminate the search without considering the remaining elements.
    index += 1
  end while
  return None

The command terminates both the loop and the entire function. It returns the value of the expression that follows the return keyword.

The last line in this function’s body is only ever executed in case the loop didn’t hit the early return.

In Scala, methods with return need an explicit return type annotation.

In this ebook, we seldom use return.

A bit more about return

Many Scala programmers look askance at return and avoid using it. This has to do with writing clearer code and the fact that return isn’t strictly needed for anything.

return commands may make it harder to follow the steps of a program (the program’s control flow). This is a risk especially if the code verbose, with many nested constructs. A reliance on return may also lead you to write such needlessly complicated code.

It’s generally considered a good programming practice to split a program in small, cleanly delimited subprograms. If you do that, there is usually little temptation to use return. Moreover, many languages, including Scala, have various elegant alternatives to the “loop and return” approach. These techniques include higher-order methods that process only a part of a collection (such as find, takeWhile, and exists) as well as recursion (Chapter 12.2); they make return largely redundant. Higher-order methods and recursion are particularly common in the functional programming style (Chapter 11.2) but they aren’t unique to it.

It’s not a mortal sin to put a return in your Scala program, especially if your code is otherwise nicely written.

(There are people who are stricter about this matter and make a good case for it. The more functional one’s programming style is, the more sense it makes to avoid return.)

A tangent on StarCraft and return

In his blog post Whose bug is this anyway?!?, game developer Patrick Wyatt is kind enough to recount a past blunder: he didn’t initially notice a bug in the StarCraft game even though it was “trivial”. It’s a nice read.

The error involved a return command that terminated a subprogram early in case a particular condition was met. However, another section of code many lines further down in the same subprogram was written without consideration of the fact that that code won’t run at all if an early return had already triggered.

A particularly noteworthy thing about this cautionary tale is that the conditional return was followed by a long sequence of other commands all within the same subprogram. All those commands were implicitly dependent on the return way above. return is dangerous when a program isn’t split into small enough functions.

A bit more about break

../_images/breaking_bad.png

Even more Scala programmers frown at break than at return.

For the most part, break has been criticized on similar grounds as return has. The additional complaint is this: assuming you do wish to break out of a loop for some reason, and further assuming your code is appropriately divided in small functions, each with its own cleanly delimited purpose, then you don’t need break; you can just return your way out of the loop.

If you feel you need break, you should first consider if you might be able to place your loop in a function and use return to terminate it. (And then you can consider whether there might be a better alternative to return as well.)

More kinds of loops — for?

Some programming languages provide a different sort of for loop that has separate “slots” for initializer code, the loop-controlling condition, and the code that advances the loop towards termination. In a Java program, for instance, you can write this:

// This is Java, not Scala.
for (index = 0; index < myString.length(); index += 1) {
  // Do the loop’s actual job here.
}

Scala doesn’t have that sort of for loop. On the other hand, Scala’s for expressions are capable of many other tricks, which you’ll learn about later.

More kinds of loops — do?

Some programming languages have a kind of loop that begins with the word do and executes the loop body one or more times (cf. while loops, which execute the body zero or more times). Old versions of Scala used to have that, too, but it’s since been discarded as superfluous. If you insist on writing a loop in modern Scala that executes the contents of the loop once before checking the looping condition for the first time, there’s this “trick” that you can do with a while loop:

def printAtLeastOneSquare(limit: Int) =
  var number = 1
  var square = 1
  while
    println(square)
    number += 1
    square = number * number
    square <= limit
  do ()

That function prints out at least one line of output even if limit isn’t positive. Between the while and do keywords, where the condition goes, we have a whole block of code that begins with the loop’s actual contents and ends with the conditional expression that controls the loop. On each cycle through the loop, the three other lines get executed first, and the condition on the fourth line of the block is checked only afterwards, so the entire block gets executed at least once. After the do keyword, where we’d normally have a proper loop body, we now have just some empty brackets, so nothing happens there.

Readers of such code may find it confusing, though. We do not recommend this style.

Feedback

../_images/be_back.png

The robots will return in Chapter 10.3’s voluntary assignment.

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 and so 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, 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 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 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.

a drop of ink
Posting submission...