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 do I bring my graphical application to
life? How do I make it react to the user’s mouse clicks and key
Topics: GUI events of different kinds. Event handling in a GUI.
What Will I Do? Very concrete things. The chapter consists
largely of example programs and programming assignments.
Rough Estimate of Workload:? An hour or more. There
are a lot of optional assignments on offer.
Points Available: A65.
Related Modules: IntroApps, FlappyBug.
In this chapter, we’ll get the ladybug moving and do other nice things. But let’s start
with a very simple example.
Some of the programs in this chapter make use of a simple counter. Such a counter can
keep track of any quantity that increases by one at a time, such as the number of a
user’s mouse clicks in an application.
The REPL session below creates a counter that starts at zero and increases by one every
time its effectful method advance is invoked:
val firstCounter = Counter(0)firstCounter: Counter = value 0
firstCounter.valueres0: Int = 0
firstCounter.advance()firstCounter.valueres1: Int = 1
firstCounter.advance()firstCounter.advance()firstCounter.valueres2: Int = 3
The initial value doesn’t need to be zero:
val secondCounter = Counter(100)secondCounter: Counter = value 100
secondCounter.advance()secondCounter.advance()secondCounter.advance()secondCounter.valueres3: Int = 103
Given what we know from earlier chapters, class Counter is easy to implement:
class Counter(var value: Int):
def advance() =
this.value = this.value + 1
override def toString = "value " + this.value
The “path” of a stepper is predetermined.
The variable value in class Counter has a role that’s a bit different from any of the
other variables we’ve used so far (cf. the roles of variables from Chapter 2.6). Starting
from a given number, it always increases by one. With the same initial value, the sequence
is invariably the same; e.g., 0, 1, 2, 3, etc.
A stepper (askeltaja) is a variable whose value advances along a preordained
sequence of values. Assuming we know the initial state, we also know what the sequence
is. A typical stepper follows a sequence of increasing or descreasing integers, but other
kinds of steppers exist, too.
Steppers are very common. Our counter class shows an archetypal use case for a stepper:
we want to track an increasing quantity. Later in O1, you’ll see another frequent use:
keeping track of an advancing ordinal number.
Just like the value of a gatherer (Chapter 2.6), a stepper’s new value depends on its
previous value. However, a stepper’s value doesn’t depend on external factors (such as
inputs) but always follows its preset path.
As an experiment, let’s write a program that counts the user’s mouse clicks and makes
visible changes to the GUI display as the clicks accumulate.
A single Counter object will do as our domain model. Let’s make our GUI draw a circle
that grows in size with each click.
We can get started by defining a GUI view and a main function as taught in Chapter 2.7:
val clickCounter = Counter(5)
val blueBackground = rectangle(500, 500, Blue)
object clickView extends View(clickCounter):
def makePic = blueBackground.place(circle(clickCounter.value, White), Pos(100, 100))
@main def runClickProgram() =
Our domain model is a Counter object whose value starts at,
makePic constructs an image by placing a white circle against
a blue background. The circle’s diameter equals the counter’s
current value (initially five).
To make our GUI react to mouse clicks, we need to define an event handler
(tapahtumankäsittelijä) on it. An event handler is a piece of code that is invoked
whenever a new event (tapahtuma) is observed; events include mouse clicks and
movements, key presses, and so forth.
Let’s add an event-hander method on our clickView object:
object clickView extends View(clickCounter):
def makePic = blueBackground.place(circle(clickCounter.value, White), Pos(100, 100))
override def onClick(locationOfClick: Pos) =
println("Click detected at " + locationOfClick + "; " + clickCounter)
Our event handler is a method called onClick. Any View object
is capable of detecting events in the GUI; it calls this method
whenever a click event occurs. We’ll take a closer look at the
method’s code momentarily.
You can find this program in package o1.counter in the IntroApps module. Run the program,
click about with the mouse, and observe what happens. Keep an eye on both the graphical
window and the text console.
Now that you’ve tried the program, let’s inspect the event-handler:
override def onClick(locationOfClick: Pos) =
println("Click detected at " + locationOfClick + "; " + clickCounter)
To react to mouse clicks, we must give the method exactly
this name. The Pos parameter is also important. Now the GUI
library recognizes our method as the one to call when an event
occurs and passes the event’s coordinates as a parameter.
The method’s body defines what we want this application to do
when a click happens. Here, we command our counter to record the
click and also report the event in the text console.
Many event handlers receive additional information about the
event as a parameter. In this case, the parameter informs the
event handler of the coordinates where the mouse was clicked.
This application does nothing with this information apart from
printing it out.
We’re free to name the event handler’s parameter variable as we
please, just like we’re free to name any other local variables.
We must prefix the method with override just like you’ve done
with toString methods (Chapter 2.5). This is because the View
class already defines a number of default event handlers, onClick
being one of them. The default handlers’ behavior is to simply
ignore all events, because there is no generic way to react to an
event; the desired reaction depends entirely on the application.
So what we do here is override the default implementation with
our own application-specific method.
We didn’t need to explicitly call onClick anywhere. From our perspective, the method is
invoked automatically whenever the user clicks. This automaticity is given to us by the
View class. Each View object knows how to function as its own event listener
(tapahtumankuuntelija): it is notified of events that apply to it and calls event
handlers such as onClick.
We can react to a key press just like we could to a mouse click. We just need a slightly
different event handler:
override def onKeyDown(pressedKey: Key) =
println("Pressed down: " + pressedKey)
This event handler must be named onKeyDown. It receives a
value of type Key as a parameter. Different Key objects
correspond to the different keys on a keyboard.
This example handler just prints out a report of which key
Take out the version of FlappyBug’s GUI that you wrote earlier (Chapter 2.7). As things
stand, the program has a flappyView object that knows how to produce a picture of the
game world, but nothing else.
On that flappyView object, add the onKeyDown event handler
from the previous section. Run the program and note the reports
it produces in the text console on every key press.
Remove the print command from the event handler. Instead call the
activateBug method of the Game object. Now pressing any key on
the keyboard should activate the bug that’s linked to the Game.
Run the modified program. Witness:
The bug moves!
The bug flies off-screen after just a few key
The bug doesn’t fall. The obstacle doesn’t
move. Time stands still in the game world.
You haven’t yet called the timePasses
method of the Game object. (We’ll get
to that momentarily.)
Submit your code.
A+ presents the exercise submission form here.
An event doesn’t necessarily have to reflect an action by the user. The passing of a
moment is an event of sorts, too.
The package o1.counter in IntroApps contains a “Ticking App” that counts clock ticks
rather than mouse clicks. Run the program and see below for an explanation of how it
val tickCounter = Counter(0)
val blackBackground = rectangle(500, 500, Black)
object tickView extends View(tickCounter):
def makePic =
blackBackground.place(circle(tickCounter.value, White), Pos(250, 250))
override def onTick() =
@main def runTickProgram() =
This program doesn’t have an onClick handler; it has onTick
instead. This method takes no parameters.
The View object uses a timer that fires a clock tick roughly 24 times per second. Every
time this happens, the view calls its own onTick handler, which makes our counter advance.
Edit the program’s makePic method so that:
The shape that “approaches” the user isn’t a circle but a square
whose edge length equals the counter’s current value.
The square not only grows in size but also rotates one degree
clockwise on each clock tick. Use the clockwise method
introduced in Chapter 2.3 to rotate the square, and pass in
the counter’s value as a parameter.
Test the edited program. Then try changing the clock speed: give the View object the
number 50 as a second constructor parameter. Now onTick gets called about fifty times
per second, causing the shape to gyrate and grow faster.
More things to try
Try different clock speeds. A larger number speeds up the ticking,
a smaller number slows down the program. A value between zero and
one means the application’s clock ticks at a rate slower than one
tick per second.
Try a different picture in place of the square. For instance,
scaling a rotating face.png to an increasingly large size makes
for a rather disturbing animation. To adjust an image’s size, you
can use either the scaleBy method from Chapter 2.3 or scaleTo,
which expects the desired width and height as parameters (in pixels).
Who calls makePic and when?
I guess View updates itself, since the
pictures move in the window even though I
haven’t called makePic...
Does a View call makePic whenever any of
the onSomeEvent methods has been called,
like onClick or onTick?
A View object is responsible for updating the visible graphics
whenever one of its event-handler methods is called.
After each event, the View calls its own makePic method and
displays the image that makePic returns. makePic gets called
in this fashion on clock ticks and on user-generated GUI events
once you’ve started the view. You must define a makePic
method on any View that you use.
Any onTick method that you define gets called multiple times per
second (unless otherwise specified). It triggers a makePic call
(Even though you don’t need to call a View’s event-handling
methods and makePic directly, they are methods just like any
other. The tester code in A+ doesn’t actually start your GUIs
and display them onscreen; it calls makePic, onTick and the
Implement an onTick method on the flappyView object. The method should simply call
the timePasses method of the app’s game object. (Since this is the onTick method,
the view object will automatically call it on every tick of the clock.)
FlappyBug is starting to look like a game, but there’s much to be done still. In this
assignment, you’ll improve the app as follows:
Prevent the bug from rising higher than the top edge of the
visible game world. The bug’s center must not have a negative
Prevent the bug from burrowing into the ground. The bug’s
center must not have a y coordinate in excess of 350.
We recommend the following approach, which is both convenient and elegant. There are
other ways to solve the assignment, too; in programming, there always are.
Add an effectful method move in class Bug:
It takes a Double parameter that indicates how much should be
added to the bug’s y coordinate.
It places the bug at new coordinates, which it computes from the
old ones by adding to the y coordinate as indicated. A positive
parameter value sends the bug downwards, a negative value upwards.
Reimplement the methods flap and fall so that each of the two calls move, passing
in the appropriate number. These methods should continue to do exactly the same as before
even though their implementation is different. Each method is very simple to implement by
In fancy terms, what you do here is refactor (refaktoroida) your program. Refactoring
is the modification of a program so that its quality improves but its functionality stays
the same. A common reason to refactor code is to make it easier to extend or modify.
After refactoring code that works, it’s wise to check that it still works; this is called
regression testing (regressiotestaus). For the present, we’ll accept a trial run as
sufficient testing. Run your program; it should work as before.
Every Pos object has a clampY method. It receives two numbers as parameters, which
define a lower and upper bound for the y coordinate:
val testPos = Pos(10, 50)testPos: Pos = (10.0,50.0)
testPos.clampY(5, 30)res4: Pos = (10.0,30.0)
testPos.clampY(100, 200)res5: Pos = (10.0,100.0)
testPos.clampY(0, 100)res6: Pos = (10.0,50.0)
clampY returns a new position whose x coordinate is the same as
that of the original Pos but whose y coordinate has been squeezed
into the given bounds. In our example, the bounds are 5 and 30, so
the original’s excessive y coordinate gets replaced by 30.
The same principle applies if the original coordinate is smaller
than the lower bound.
If the coordinate is already within bounds, the result equals
the original Pos.
There is, unsurprisingly, also a clampX method, but you won’t need it now.
testPos.clampX(100, 200)res7: Pos = (100.0,50.0)
With the groundwork done, the actual solution is but a few characters long.
Our twin goals are to prevent the y coordinate from growing too large and to prevent
it from growing too small. You can address both goals at once by clamping the bug’s y
coordinate to the desired interval.
Make that small change in the move method.
What about flap and fall? If you did as suggested in Phase 2 above, those methods
now also abide by the rules, since their implementation is based on move, whose code
now governs all the bug’s movements.
An optional hint
Show the hintHide the hint
Make sure to assign the right value to the variable that stores
the bug’s location: the new location should be affected by both
the bug’s movement and the clamping.
As you specify that sequence of operations, keep in mind that
Pos objects are immutable (Chapter 2.5). Be sure to apply
the latter operation to the result of the former.
Just hopping up and down is not fit for a bug.
To introduce a sense of forward motion into our game, we could make our bug move sideways
along the x axis. But how about a different approach? Let’s instead make the background
slide from right to left. The Pic class has a method that’ll serve us nicely:
val testPic = circle(200, Red)testPic: Pic = circle-shape
val shifted = testPic.shiftLeft(25)shifted: Pic = circle-shape (transformed)
The illustration on the right shows the new image returned by shiftLeft, in which the
original image’s contents have been moved leftwards by the given amount. The left-hand
bit that would have otherwise vanished now appears on the right.
You can probably guess what’s coming: we’ll take the familiar picture of sky, ground, and
tree, and shift it leftward as the clock ticks, yielding new versions of the background.
Make three changes to FlappyBug’s GUI.
Add a variable to the flappyView object. Call it background.
Initialize it with the value of scenery:
var background = scenery
This is a var. You’ll use this variable to keep track of which
image is currently used as the game’s background. When the game
starts, the background is the familiar image with the tree right
in the middle.
Reminder: to make background a variable on the flappyView
object, put the variable inside flappyView’s definition. But
don’t put it within makePic or the other method definitions —
that would make it a local variable that only exists while the
method is running.
In onTick, add the following command that updates the background:
this.background = this.background.shiftLeft(2)
What this does is shift the background a couple of pixels left
every time the clock ticks.
If you wish, you can also define a constant and use it instead
of the magic number two.
The above commands do create new versions of the background image
and adjust the background variable just as intended. Nevertheless,
if you run your program now, you’ll find its outward behavior
unaltered. This is because makePic still uses the original
scenery to construct the image that it shows to the user.
Substitute background for scenery, and voilà!
Our bug falls at a steady, slow, unnatural pace. Let’s make it accelerate towards the
ground between flaps. Here’s the basic idea:
The bug will have a velocity: how many pixels it moves vertically
on each clock tick. A positive velocity stands for downward
movement; a negative velocity moves the bug upwards.
When the bug flaps its wings, its gets an upward velocity. That is,
it doesn’t immediately change location on a wing flap; instead, its
velocity changes (see below for details).
On each tick, we add two to the bug’s speed, pulling it ever more
In class Bug, add an instance variable that keeps track of the bug’s current vertical
velocity: how many pixels per tick does the bug fall or rise per tick?
Set the variable to an initial value of 0.0. Give it the name yVelocity.
Edit the flap method so that it no longer moves the bug fifteen pixels upwards or
indeed anywhere else.
In the existing version of the program, flap’s parameter indicates how much the bug
moves right away. Modify the method so that the parameter instead gives the bug an
upward velocity. For instance, if you pass 15 as a parameter to flap, the bug gets
a negative velocity of -15. Assign that value to yVelocity.
In the modified program, the flap method must not move the bug at all! The method only
adjusts the bug’s velocity.
Also note that flap completely ignores what the bug’s earlier velocity was. It simply
replaces the old velocity rather than adjusting it by the given amount.
(The activateBug method in class Game should still call the bug’s flap method
and pass in the number fifteen, as before. The difference is what flap does with its
Adjust the fall method so that it:
first increases the value of yVelocity: the new value should be
two more than the old;
then moves the bug (up or down) by yVelocity’s new value. If you
wrote a move method for this class in the earlier assignment,
simply calling that method will do the trick.
A side note about move
It turns out that the helper method move is no longer quite
as useful in this version of FlappyBug as it was in the earlier
one. Such things happen as programs evolve. Even so, it’s okay
to leave move in and call it from fall.
We’ll return to FlappyBug in Chapter 3.2.
The optional activities below will teach you, among other things, how to make your
application respond to mouse movements. That isn’t necessary for O1, but you’ll probably
want to try your hand at some of these assignments anyway.
Optional assignment: something’s stuck to my mouse
photo: Dwight Kuhn
In this toy example, we’ll use a simple class to model an object that we’ll
call a burr:
var location = Pos(0, 0) // most-recent holder
A burr object’s only attribute is its location, which is mutable:
val testBurr = Burr()testBurr: Burr = o1.burr.Burr@34ece05e
testBurr.locationres8: Pos = (0.0,0.0)
testBurr.location = Pos(10, 50)testBurr.locationres9: Pos = (10.0,50.0)
Within the IntroApps module you can find the above class as well as a file
named BurrApp1.scala. Build on the starter code in the file to produce
the following application:
The domain model is a single burr object.
The GUI is a View that draws a green circle (burrPic)
on a white background (background) at the burr’s location.
The view’s makePic method must return
an image where the burr pic is correctly
positioned against the background.
Please make sure to use the name window
for your specialized View object. (This
helps us with the automatic assessment.)
The view has the following event handler:
It’s called onMouseMove and receives
as its only parameter a Pos object
that indicates the mouse cursor’s current
position (just like onClick above).
It assigns the mouse location to the burr’s
location attribute. The burr will thus
follow the mouse.
If you want, you can also include a
command in the body of onMouseMove
that prints out the parameter. This makes
it easier to observe how often this event
handler is called as you move the mouse
within the GUI window.
To clarify: the onMouseMove method does no image manipulation at all.
It’s makePic’s job to form each new image, using the latest coordinates
that onMouseMove has assigned to the burr.
Follow-on assignment: crosshairs
Instead of the green circle, let’s draw two lines that meet at the mouse
Lines are easy to draw with the line function from package o1. This
function works much like circle, rectangle, and the rest. Here’s an
val myLine = line(Pos(0, 0), Pos(150, 100), Red)myLine: Pic = line-shape
val backdrop = circle(200, LightBlue)backdrop: Pic = circle-shape
val myPic = backdrop.place(myLine, Pos(20, 20))myPic: Pic = combined pic
The outcome should look like this. The lines move
with the mouse cursor.
Open BurrApp2.scala in package o1.burr.crosshairs and copy the previous
assignment’s solution there. Then edit makePic to draw not burrPic but
two black (Black) lines:
One of the lines should start at the top edge exactly above
the mouse cursor and reach all the way straight down to the
bottom of the view.
The other line should begin at the edge to the left of the
cursor and reach all the way to the right-hand edge.
Instructions and hints:
You can use place to position the lines. As you do so, note
that the method places the starting point of the line — not
its middle — at the given coordinates.
There’s no need to make any changes to onMouseMove.
Follow-on assignment: arithmetic on Pos objects
In BurrApp3.scala from package o1.burr.pointer, write an application that
resembles the previous two but doesn’t draw a burr or crosshairs. Instead, it
draws a single black line from the view’s center towards the mouse cursor —
but only until the halfway point between the center and the cursor. That is,
the line “points towards” the cursor but doesn’t reach it.
This assignment calls for a bit of arithmetic on coordinates. We recommend that
you use the methods add, multiply, and/or divide from class Pos. You
can first experiment with them in the REPL:
Try calling add so that you pass a reference to another
Pos object as parameter: pos1.add(pos2).
Try multiplying or dividing both coordinates by a number:
pos1.multiply(number) or pos1.divide(number).
Follow-on assignment: A slow burr
In BurrApp4.scala from package o1.burr.slow, write an application where
a green circle follows the mouse cursor much as in BurrApp1. However,
instead of instantly appearing where the mouse currently is, the burr will
now gradually glide towards the cursor.
Again, take the code of BurrApp1 as your starting point. Make these changes:
Give the window object an additional variable that keeps
track of the mouse cursor’s most recent observed Pos.
You can initially set it to (0,0). Call the variable
latestCursorPos, for example.
Edit onMouseMove so that it does nothing more than assign
its parameter value (i.e., the cursor’s current position) to
the latestCursorPos variable. In other words: This app doesn’t
actually move the burr whenever the mouse moves. At that point
of time, it simply records the latest movement of the mouse.
Add an onTick method that moves the burr. The burr’s new
location is the point that is ten percent of the way from
its old location towards the latest cursor position.
For instance, if the burr is now at
(10,20) and latestCursorPos is (100,100),
the burr moves to (19,28).
Here, too, you can use the Pos methods
mentioned in the previous assignment.
Optional assignment: a painting app
Take a look at the following pseudocode class that represents “art projects”. An art
project, here, is an image that evolves incrementally as little dabs of color are added
to it. The pseudocode already contains quite a bit of actual Scala, too.
class ArtProject(canvas: Pic):
var image = canvas // gatherer
var brush = circle(10, Black) // most-recent holder
def paint(where: Pos) =
Form a new picture by taking the current image and positioning the brush pic
onto it at the given coordinates. This new picture becomes the new image.
The variable image is a gatherer: it initially holds just
the original canvas, but small images (“brush strokes”) are
gradually placed on it. The image stored in the variable
is a combination of the canvas and all the brush strokes that
have accumulated so far. (At least, this is what the variable
should do, but we haven’t yet implemented the method that
actually adds the brush strokes.)
The “brush” is a picture. A new copy of the brush is positioned
onto the current image whenever the paint method is invoked.
The default brush is small, round, and black.
The algorithm for adding paint to the canvas has been given
as pseudocode here. You’ll need to implement it yourself in
the o1.art package, which you’ll find in the IntroApps module.
You’ll also find a GUI in PaintingApp.scala. It creates a View of an
ArtProject object that serves as the domain model. The given code is a
good start, but it lacks an event handler.
To summarize, here is what you need to do:
Implement the paint method of class ArtProject.
Add an onMouseMove handler to the GUI. It should
simply call the paint method of the art project
that is displayed in the View, so that a brush
stroke appears at the mouse cursor.
Test your program.
Follow-on assignment: changing colors
Modify the painting app so that the user can change the drawing color with a mouse
First edit class ArtProject so that it keeps track of the currently active color
and cycles to the next color on request. More specifically:
Add these two instance variables at the top:
var colorIndex = 0
val palette = Buffer(Black, Red, Green, Blue)
The palette variable holds a reference to a buffer that stores
all the colors available to the app’s user.
At any given time, a single color from the palette is active;
the variable colorIndex stores the index of the active color.
In this assignment, we’ll use colorIndex as a stepper that
advances through the palette in order and wraps back to the
beginning: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, etc.
Add an effect-free method named drawingColor that takes no
parameters and returns the currently active color. That is,
the method returns the Color indicated by colorIndex
Implement an effectful method changeColor:
It advances colorIndex to the next integer.
(Use the modulo operator to wrap the number
back to zero.)
It changes the value of brush to a
differently colored circle of the same
size. (Call drawingColor to get the new
It takes no parameters (but as an effectful
method, requires an empty parameter list;
Finally, add an onClick event handler to the GUI. This method
should (ignore its Pos parameter and) simply call changeColor
on the art project. See ClickingApp at the beginning of this
chapter for guidance.
Follow-on assignment: GUI events in more detail
Modify the program from the previous assignment. In the new version, the user
still clicks to change the drawing color. However, the new color isn’t the
next one in the palette. Instead, the color is determined by the number of
successive clicks: a single click selects the first color in the palette,
a double-click the second one, a triple-click the third one, and so forth.
First, edit class ArtProject: add an Int parameter to changeColor
and modify the method’s body so that it doesn’t cycle to the next color
but instead sets colorIndex from the parameter.
Then replace the onClick method in painterView with this one:
override def onClick(clickEvent: MouseClicked) =
Our earlier onClick methods received just the click’s location
as a parameter. In many cases, that’s all the information about
the event that we need. But sometimes we do want to take a more
detailed look at a GUI event, say, to examine the number of
In such cases, we can define an event handler that
receives a reference to an object that represents the
entire event, as the MouseClicked object does here.
A MouseClicked object provides access to various
attributes of the event. Here, all we need is clicks,
which is the number of successive clicks as an Int.
Test your program. Try clicking a lot of times in quick succession.
Did you take this possibility into account when you rewrote changeColor?
If not, do something about it now; if yes, you may wish to try and
see what would have happened if you had failed to consider high
If you wish, you can continue exploring event handlers and event
objects on your own. For example, the documentation
of class View lists a number of event-handler methods (whose
names start with on).
When a user interacts with a graphical user interface, a GUI event
is fired. A GUI event can be a key press or a mouse movement, for
instance. The ticks of an application’s internal clock can be
An event handler is a subprogram that receives information about
events that have occurred and determines what the program does
when that happens.
An event handler may receive parameters such
as the precise location of an event.
You can define event handlers on the View
objects that we use in O1.
Writing graphical programs is fun.
Links to the glossary: model, user interface; graphical user interface
(GUI); GUI event, event handler, event listener; refactoring; stepper.
You can use the tools just introduced to do a lot more than what
was required or suggested. Go forth and create! Edit one of the
example programs or invent something entirely of your own creation.
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.
The FlappyBug game is inspired by the work of Dong Nguyen.
The optional assignment where you draw a line from the center towards the cursor is
a Scala variant of a programming exercise by Daniel Shiffman.
Our domain model is a
Counterobject whose value starts at, say, five.