Luet oppimateriaalin englanninkielistä versiota. Mainitsit kuitenkin taustakyselyssä
osaavasi suomea. Siksi suosittelemme, että käytät suomenkielistä versiota, joka on
testatumpi ja hieman laajempi ja muutenkin mukava.
Suomenkielinen materiaali kyllä esittelee englanninkielisetkin termit. Myös
suomenkielisessä materiaalissa käytetään ohjelmaprojektien koodissa englanninkielisiä
nimiä kurssin alkupään johdantoesimerkkejä lukuunottamatta.
Voit vaihtaa kieltä A+:n valikon yläreunassa olevasta painikkeesta. Tai tästä:
About This Page
Questions Answered: How do I launch a custom command (that’s been
defined by someone else)? How do I pass parameters to the command
and see what it accomplishes?
Topics: Subprograms. Effectful vs. effect-free subprograms. Calling
a subprogram: parameters and return values. Nested calls. The Unit
What Will I Do? Program in the REPL and read.
Rough Estimate of Workload:? An hour, or perhaps an hour
and a half. In addition to the assignments, there is some knotty
(but useful) terminology to untangle.
Points Available: A20.
Related Projects: Subprograms (new).
Notes: This chapter makes occasional use of sound, so speakers or
headphones are recommended. They aren’t strictly necessary, though.
This and next two chapters are concerned with subprograms (aliohjelma).
A subprogram is an implementation of a particular piece of functionality. For instance,
a subprogram may calculate a result, record some useful data in the computer’s memory,
or print out a message. Or it may perform a specific combination of such tasks.
Programmers can create new subprograms, then use what they created. They can also use
subprograms created by other programmers. A full program, such as the GoodStuff or Pong
applications, contains various subprograms.
But you’ll have to wait a bit before we can tackle how those apps work. For now, let’s
proceed as follows:
Subprograms are the last missing piece that we’ll need in Week 2 as we begin to learn
about something called “object orientation” and how it helps us put together entire
For this chapter, you need a new Eclipse project called Subprograms. It contains an
assortment of subprograms for you to experiment with. The instructions below recap (from
Chapter 1.2) how you can load the project into your workspace and import its contents
in the REPL.
Load the project into Eclipse:
Start up the REPL like this:
Enter the following commands in the REPL. Note
Suppose we have some numbers — the results of a series of scientific measurements, say —
stored in a buffer. Like so:
val results = Buffer(-2, 0, 10, -100, 50, 100, 5, -5, 2)results: Buffer[Int] = ArrayBuffer(-2, 0, 10, -100, 50, 100, 5, -5, 2)
Let’s further assume that the negative numbers in our buffer indicate failed measurements
and we wish to discard them.
It’s possible to define a subprogram that takes care of removing all negative numbers
from any given buffer. Indeed, a subprogram just like that has been defined for you in
the Subprograms project. It’s called removeNegatives and works like this:
Instructing the computer to execute a particular subprogram is known as calling
(kutsua) the subprogram (or invoking the subprogram; or applying it). It’s easy
to call removeNegatives:
This command that invokes removeNegatives doesn’t itself have a value in the same
sense as, say, the expression 1 + 1 does. (Well, at least the command doesn’t have a
meaningful value; more on that later.) That’s why the REPL doesn’t respond with any
output. However, we can take a look at the value of the variable results and verify
that the subprogram did indeed modify the buffer that the variable refers to:
1 + 1
resultsres0: Buffer[Int] = ArrayBuffer(0, 10, 50, 100, 5, 2)
The preceding example must have felt a bit familiar. The way we invoked removeNegatives
just now is very similar to how you’ve already printlned and played: first, the name
of the command; then, a parenthesized parameter expression. This isn’t a coincidence.
Even though we didn’t attend to the fact at the time, println is a subprogram just
like removeNegatives is. It’s just that println is a general-purpose subprogram
defined to be a part of Scala whereas removeNegatives is an example subprogram invented
for the purposes of this one ebook chapter. Similarly, play and show from Chapter 1.3
are subprograms, too.
Now let’s take a look at a rather different sort of subprogram.
The same project contains a subprogram named average, which has a simple purpose:
you pass two numbers to it as parameters, and it computes their average. This
subprogram returns (palauttaa) a value:
average(5.0, 11.0)res2: Double = 8.0
Here are a few more examples of calling this subprogram. As shown
in the examples, you can use a subprogram-calling expression as a
component of a longer expression:
val first = average(5, 1) + 2.1first: Double = 5.1
val second = average(10.9, first) + average(-5, -10) - 1second: Double = -0.5
1 + average(second + 1, 1)res1: Double = 1.75
You’ll get to see many more examples of subprograms in just a moment, but first, let’s
stop to consider the attributes of the subprograms that you’ve already seen.
This chapter has introduced two very different subprograms:
We have also used the subprogram println to output text. When a println command is
executed, it has an effect on the world in the sense that the output visible onscreen
changes in an observable way. This is why we’ll place println in the category of effectful
subprograms along with removeNegatives. The subprograms play and show from Chapter 1.3
are similarly effectful.
That chapter also introduced circle and rectangle, which are subprograms too. These
subprograms, like average, are effect-free. Just as average merely computes and returns
a numerical value based on of the parameters that you give to it, circle and rectangle
merely compute and return a picture based on the parameters they receive.
For any subprogram, you can ask: when you call the subprogram, does anything observably
change? (We won’t count time passing or receiving a return value as a change.) The answer
tells you whether the subprogram is effectful or effect-free. This classification already
highlights the fact that different subprograms can do some very different things. As we
go on, you’ll see that this question has a profound significance in programming. One may
even profit from programming in a way that relies exclusively on effect-free subprograms
(Chapter 10.2). But let’s not get ahead of ourselves; right now, we can use the
classification to illuminate a few basic terms and concepts.
In a number of programming languages, it’s customary to call all subprograms functions
(funktio), whether they are effectful or effect-free. Scala is one such language. In the
rest of this ebook, the word “function” will show up often; we’ll use it to mean a subprogram.
The word sounds very familiar, and there are reasons why that is so. However:
Many beginner programmers have tripped over the concept of function because of the
mismatch between what programmers and mathematicians mean by the word.
It’s true that effect-free functions resemble the functions from school mathematics.
Given a mathematical function f(x), just determining its value for a particular x
doesn’t change any stored data or output anything onscreen. Similarly, an effect-free
function just takes in some parameter values and produces a result (a return value),
and that’s it.
However, a Scala function may, when called, generate output or otherwise affect program
state. We must remember that what we programmers term a function can also be an effectful
Moreover, the functions that we use in programming, even effect-free ones, differ from
familiar mathematical functions in that we don’t merely define a relation between inputs
and outputs like f(x) = x + 1. Our functions also implement the step-by-step processes
(algorithms) that compute the return values. The next chapter will illustrate this in
Here is a table of the kinds of functions we have just discussed. Some bits of text have
been underlined; you can mouse over them to view additional explanations.
This section will take you through a whole cavalcade of example functions. This should
demonstrate the variety of things that functions can do while letting you practice
reading program code that invokes functions.
We’ll use some of Scala’s built-in functions as well as a number of example functions
created for O1.
The REPL interaction below features several Scala functions that instruct the computer to
Some of the functions are probably familiar to you from calculator apps, such as abs
(absolute value), pow (power), sqrt (square root), and sin (sine). All of these functions
are located in the package scala.math, so we need to import them either individually or,
as below, all at once.
import scala.math._import scala.math._
Now we can easily call the functions:
abs(-50)res2: Int = 50
pow(10, 3)res3: Double = 1000.0
sqrt(25)res4: Double = 5.0
sin(1)res5: Double = 0.8414709848078965
The functions max and min return the greater and lesser of their two parameters,
max(2, 10)res6: Int = 10
min(2, 10)res7: Int = 2
All those functions are effect-free, just as average was in our ealier example. They
only return values and don’t modify any data we’ve previously stored, or print or play or
Try calling at least some of the functions in the REPL. You can also experiment with the
following: other trigonometric functions (cos, atan, etc.), cbrt (cubic root),
floor (rounds down), ceil (rounds up), round (rounds to closest), hypot
(hypotenuse of two given legs), and log and log10 (logarithms). For whole list of
functions in the package, see Scala’s documentation.
In Chapter 1.1, we already touched on the concept of library (kirjasto): a selection
of components for programmers to use in different projects. Scala’s mathematics package is
an example of a library, and we can call functions such as the above library functions.
Now please don’t go off trying to memorize all these library functions, let alone all the
thousands of others out there, even though no doubt you’ll be needing some of them later
on. You can check the names later from the Scala documentation or this ebook. When it
happens, and it does happen, that a function is so frequently useful that you need it
repeatedly, you’ll end up remembering it without trying. (All that being said, here’s a
hint: you’ll find min and max repeatedly useful in the forthcoming chapters.)
Student question: Do I waste memory if I use an underscore in an import?
No. An import statement is there to put on record what particular
names mean within a particular piece of code. For instance,
importing scala.math._ indicates that the names min, max,
sqrt etc. refer to functions in that package.
Yes, it’s true that the computer must hold the tools that you use
in memory, functions included. But in terms of a program’s runtime memory
usage, what matters is the tools you actually use, not the import
commands that express your intention to use them.
A function can make use of external resources such as files or networked computers. The
following example function from o1.subprograms finds out which movie is in a particular
position in the all-time Top 250 according to the votes cast on the IMDB web site.
imdbMovie(3)res8: String = The Godfather: Part II
imdbMovie(1)res9: String = The Shawshank Redemption
The example function works even if you don’t have a network connection, because it’s been
designed to take its information from the folder top_movies that comes with the
Subprograms project. (This also means that the movie info isn’t quite up to date.)
Use the function imdbMovie to identify the 150th best movie ever
according to IMDB. Here, we number the movies in the everyday fashion
from one upwards, so the two movies picked out above are the third
and first on the list, respectively.
(Remember to import o1.subprograms._. You’ll need to do this again
if you’ve relaunched your REPL after last importing.)
Enter the name of the 150th best movie here:
The function imdbBestDirectors also uses the top-movies list.
It sorts movie directors by how many of their movies appear on
the list and returns a string containing a list of directors.
The function expects to be given a single integer parameter that
serves as the lower limit for inclusion; for instance, given the
parameter value 2, the return value will include only those
directors who have at least two movies in the Top 250.
Use imdbBestDirectors to discover who has the most movies on
the list. Enter the name of the director here. (Actually, there’s
a tie between two directors. Pick either of them.)
Use the function imdbBestBetween to determine the best movie of
the 1950s according to IMDB. The function expects two integer
parameters: a starting year and an ending year. It returns the
name of the highest-ranking movie within the given interval.
The interval includes the two years you pass as parameters.
Enter the highest-rated movie of the nineteen-fifties here:
For a change, let’s use strings as parameters and experiment
with a function named editDistance. This function computes
the Levenshtein distance between its two string parameters.
The Levenshtein distance
is an integer that indicates how many single-character insertions,
deletions, or substitutions it takes to turn one string into another.
For example, the Levenshtein distance between the strings "beginner"
and "engineer" is three, because we can’t manage with fewer operations
(The Levenshtein distance has applications beyond spell checking.
For instance, in computational genetics, it can be used for comparing
DNA sequences. The genome of an organism can be represented as a
string whose letters (such as A, G, C, and T) correspond to different
constituents of DNA.)
Call the editDistance function, which too is defined in package
o1.subprograms. You’ll need to pass in two parameters of type
String: the two strings to be compared. Use string literals
enclosed in double quotation marks. Remember the comma.
Experiment with the function freely. Use different parameter
values. In the field below, please report the Levenshtein distance
between the strings "democrat" and "republican".
Let’s make an animation.
Define some variables as follows.
val sizeOfLamp = 250
val redLamp = circle(sizeOfLamp, Red)
val yellowLamp = circle(sizeOfLamp, Yellow)
val greenLamp = circle(sizeOfLamp, Green)
val trafficLights = Buffer(redLamp, yellowLamp, greenLamp)
The package o1.subprograms has an effectful function animate
that displays a number of images one after another, thereby turning
them into an animation. The function expects two parameters:
a bufferful of pictures; and
a positive number (Double), that
determines the speed of the animation.
A larger number results in a faster
Experiment with animate. In the field below, enter a command
that animates the contents of the buffer that the variable
trafficLights. Use the speed 1.0. If you want, go ahead and
come up with other things to animate.
The following code plays the internationally popular
melody of Frère Jacques. Try it out.
val frereJacques = "f-g-a-f-f-g-a-f-a-hb->c---<a-hb->c---cdc<hba-f->cdc<hba-f-f-c-f---f-c-f---"
Frère Jacques is commonly performed as a repeating canon using multiple
voices or instruments: each instrument begins the melody at a
somewhat different time so that the performances of the
instruments overlap each other. You can use the effect-free
function canon in package o1.subprograms to form a string
that represents such a canon. The function is defined as follows.
Here’s a nearly finished piece of code that uses canon:
val frereJacques = "f-g-a-f-f-g-a-f-a-hb->c---<a-hb->c---cdc<hba-f->cdc<hba-f-f-c-f---f-c-f---"
val instruments = Buffer(4, 1, 74, 19)
What should replace the three question marks so that the code plays
a canon using the melody and instruments indicated by the variables,
and a delay of 8?
Experiment in the REPL. In the field below, write the expression
that calls canon as requested. (Please enter just the expression
that goes where the question marks are, not the entire play
command or the return value of the function.) Use the variables
Feel free to play around with canon.
Let’s do one more exercise on passing a buffer reference as a
Experiment with the function censor, also located in o1.subprograms.
Call it and pass in these two parameters:
What does the censor function return, given this input?
Here’s one way to find out: First create a variable that refers
to the buffer. Call the censor function, passing in the text as
a literal and using the variable you just defined to refer to the
buffer of naughty words.
The code in the preceding assignment should be of assistance.
Enter all the input strings exactly as written above. You may wish
to copy and paste the returned string below so that you get it just
It’s perfectly possible to create a function that interacts with the user when it’s called.
Try out one such function, called playDoodads. This function challenges you to a game that
lets the computer show off. It expects a single string parameter that represents the player’s
name; you can use your own first name, for instance.
When you call a function, you write expressions to indicate which parameters you wish to
pass in. On the other hand, a function call is itself an expression. So it makes sense
that you can nest a function call within another:
When you would end up with lots of nested function calls, you may wish to reformat your
code to make it easier to read. Variables are an excellent tool for this. For instance,
the last line of code in the preceding animation could be replaced by these commands:
val fifthPower = pow(2, 5)fifthPower: Double = 32.0
val smaller = min(fifthPower, 100 - sqrt(100))smaller: Double = 32.0
println(abs(-5.5) + smaller)37.5
val fifthPower = pow(2, 5)fifthPower: Double = 32.0
val difference = 100 - sqrt(100)difference: Double = 90.0
val smaller = min(fifthPower, difference)smaller: Double = 32.0
val finalResult = abs(-5.5) + smallerfinalResult: Double = 37.5
When it comes to such matters of style, use your common sense. Consider, on a case-by-case
basis, what you think is best in terms of clarity and brevity. In any case, you’ll need to
get used to seeing code written in all these different styles, since programmers (and learners
of programming) read a lot of code written by others.
Examine the following expression:
max(4, 5) * min(6 - pow(5, sqrt(2) + 1), 120 / abs(-10))
When this expression is evaluated, which of the following operations take place
before the abs (absolute value) operation?
Scala (and many other languages) feature a special value known as Unit. This value
is used as the return value of functions that don’t return a value that represents
meaningful information. Such functions include println and play from before and
removeNegatives from this chapter. Technically, these functions also return a value,
though: a Unit value.
A strange name, Unit
The name Unit arrives in Scala from the tradition of functional
programming and mathematical type theory. In those circles, unit
type refers to a type that is associated with only a single
possible value and that therefore cannot represent information.
(Compare: with just two possible values, 0 and 1, we can represent
a little bit of information.) There are a number of programming
languages that use this name for the lack of an interesting value.
In certain common languages (such as C and Java), the word void
has a meaning that resembles that of Unit in Scala.
When we receive a return value of Unit from a function, there’s practically nothing
that we can do with it. You can think of it as meaning: “The function was executed but
nothing of significance was produced as a return value.” The removeNegatives function,
for instance, does modify the given buffer’s state but doesn’t produce an “output” in the
sense of a return value. For our practical purposes in O1, it’s okay think and say that
Unit means “no return value” and that functions such as println and removeNegatives
“don’t return a value” or “return nothing”.
The Unit value isn’t just a curiosity, even if it isn’t necessarily conspicuous in
the program code that you’ll write. If for no other reason, it’s good to be aware of
Unit because you’ll see it in error messages. For instance, an attempt to compute
1 + println("mammoth") begets a message to the effect that you “can’t add one to Unit”.
Moreover, the word shows up frequently in the documentation of Scala programs to indicate
that a particular program component has no significant return value.
1 + println("mammoth")
Unit return values haven’t appeared in the animations you’ve seen so far in this ebook.
But they will be shown in future animations, such as the tiny one below.
As the animation shows, println returns a value, too, even if it’s one with no content:
Beginner programmers sometimes find it hard to discern just what exactly the difference
is between returning a value and printing a value. The REPL environment, for all its good
sides, may contribute to the confusion. So let’s take a moment to underline the difference:
println(1 + 1)
The REPL evaluates whichever expression you type in. It then outputs a report of the
value of the expression without you explicitly telling it to. If the expression specifies
a function call, this means that the function gets called and a report of its return value
gets reported by the REPL. So, if you enter the expression max(3 + min(1, 4), 3),
you’ll see a printout that describes the return value of the max function. However,
min’s return value of 1, which was used while evaluating the entire expression, does not
max(3 + min(1, 4), 3)
If you use the REPL to call a function that returns Unit, the REPL will simply discard
the contentless return value.
You’ve already seen that println not only prints something, it also returns a value,
albeit only the Unit value. Nothing prevents programmers from defining functions that
both print text onscreen and return a value.
Some goals are easily reached because there is a tool available for them. For instance,
if our goal is to compute the sine or square root of a particular number, we can simply call
a library function to do that.
If we can’t find such a ready-made solution to our exact problem, we’ll form our own by
combining the tools that are available to us. If, for instance, we wish to find out the
volume of a sphere whose radius is 6371 km, we
can use arithmetic operators and the exponentiation function pow:
import scala.math.powimport scala.math.pow
4 * 3.14159 * pow(6371, 3) / 3res10: Double = 1.0832060019000126E12
Above, we evaluated a specific expression that contains specific numbers that gave us
a specific result. But if we want to handle a variety of different cases — say, compute
the volumes of various spheres of various sizes — it’s more practical to build a
custom tool for that purpose. Perhaps our tool could work like this:
volumeOfSphere(6371)res11: Double = 1.0832060019000126E12
volumeOfSphere(1)res12: Double = 4.188786666666666
You just saw one reason why we might wish to create our own custom functions: when we have
implemented a function that solves a particular, perhaps complex, task, we can easily
reuse the solution by calling the function. Moreover, writing functions helps programmers
avoid reinventing the sphere: a function, once written, can be distributed for other
programmers to use.
Functions also have a role in organizing program code into named components that are
clearly delimited. This makes the code easier to understand and modify.
One more benefit arises from how a function hides within itself the implementation of
a particular solution, whose details are unnecessary for the function’s user to know.
As long as a programmer has access to a volumeOfSphere function, they can use it even
without knowing the formula for calculating volumes. In this chapter, you yourself
have called various functions even though you couldn’t have implemented the functions
yourself or even understood their implementation given just what we’ve covered so far.
It’s been enough that you’re familiar with a few aspects of each function: what kinds
of parameters it expects, what effects (if any) it brings about, and what it returns.
In other words, functions are a form of abstraction (abstraktio) in programming.
abstract: something that concentrates in itself the essential qualities
of anything more extensive or more general; essence
—a definition of “abstract” at Infoplease.com
—a definition of “abstract” at Infoplease.com
By abstracting, we can choose to ignore details and specific cases. For instance, the
function volumeOfSphere represents the general, abstract algorithm for computing
the volume of any sphere.
Besides functions, you’ve already encountered other programming abstractions as well.
A variable is an abstraction: in the expression number + 1, the name of the variable
is there to indicate that we wish to sum two values without concerning ourselves (at
that juncture) with what specific value might be stored in the variable number.
number + 1
Function parameters promote abstraction in program code. The function sin takes a
parameter (as in sin(1)), so the programmer of that function hasn’t tied themselves up
with any specific use case of the function. Consequently, the function is more abstract
and more generally useful than a variable sineOfOne would be.
Programming revolves around the design, implementation, and use of abstractions. This
is a theme that we’ll return to repeatedly (in Chapters 2.1 and 3.1, among others).
Creating your own custom functions is something you’ll get to practice right away in
the next chapter.
Here’s the concept map from the previous chapter, newly adorned with functions:
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.
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 Piazza or the
lab sessions. We can’t guarantee that anyone will even see anything
you type here before the weekly deadline.)
Thousands of students have given feedback that has contributed to this ebook’s design.
Weeks 1 to 13 of the ebook, including the assignments and weekly bulletins, have been
written in Finnish and translated into English by Juha Sorva.
Weeks 14 to 20 are by Otto Seppälä. That part of the ebook isn’t available during the
fall term, but we’ll publish it when it’s time.
The appendices (glossary, Scala reference,
FAQ, etc.) are by Juha Sorva unless otherwise specified on the page.
The automatic assessment of the assignments has been programmed by Riku Autio, Jaakko
Kantojärvi, Teemu Lehtinen, Timi Seppälä, Teemu Sirkiä, and Aleksi Vartiainen.
The illustrations at the top of each chapter, and the similar drawings elsewhere in the
ebook, are the work of Christina Lassheikki.
The animations that detail the execution Scala programs have been designed by Juha Sorva and
Teemu Sirkiä. Teemu Sirkiä and Riku Autio have done the technical implementation, relying on
Teemu’s Jsvee and Kelmu
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 tools from O1Library (such as Pic) for simple graphical programming
is inspired by the textbooks How to Design Programs by Flatt, Felleisen, Findler, and
Krishnamurthi and Picturing Programs by Stephen Bloch.
The course platform A+ has been created by
Aalto’s LeTech research group and is largely
developed by students. The current lead developer is Jaakko Kantojärvi; many other
students of computer science and information networks are also active on the project.
For O1’s current teaching staff, please see Chapter 1.1.
This chapter does injustice to music by Neal Hefti, Mike Oldfield, and Dave Stewart. Thank you and sorry.