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: What if we didn’t use objects? How can
you program properly without directly mutating program state?
What kinds of traditions and factions are there among programmers?
What do programmers talk about when they talk about paradigms?
Topics: Some programming paradigms. Object-oriented programming,
imperative programming, functional programming.
What Will I Do? Read, for the most part.
Rough Estimate of Workload:? One hour.
Points Available: B5.
Related Modules: There is an optional assignment that involves
In the olden days of Week 2, it came up that there are different ways to program —
different programming paradigms — and that object-oriented programming is one of them.
Now that you have some experience as a programmer, it’s a good time to return to this subject.
Recognizing the main programming paradigms is part of a programmer’s general knowledge.
Even a beginner should be aware of these different styles, because it’s nearly impossible
to study programming from books and web sites without running into mentions and discussions
The word “paradigm” suggests fundamental differences in ways of thinking. Fundamental
differences in thinking tend to arouse strong emotions. The matters that we’re about to
discuss have prompted — and continue to prompt — highly divergent commentaries from
opinionated programmers who each seek to mark and expand their territory.
In this chapter, we adopt a relatively dispassionate stance. We’ll mention several paradigms,
and it is our hope that you’ll learn to regard each one without prejudice — even those
that initially seem weird or even stupid. As your programming experience grows, so will
your understanding of the different paradigms. One of the reasons why people keep crossing
swords over these matters is that reasonable arguments can be made in support of different
positions. The evidence in support of the arguments is, sadly, often purely anecdotal.
At a future time, the prevalent paradigm-based thinking may become obsolete. For now,
though, paradigms are something you should know about. If for no other reason, at least
because they frame how people speak and write about programming.
Before we consider any one paradigm more closely, let’s look at the relationships between
a few prominent programming paradigms. The short presentation also serves as a map for
the rest of the chapter.
In this chapter, we’ll discuss only a handful of paradigms. There are others; see, for
example, the relevant article on Wikipedia.
Things would be easy if we could neatly pigeonhole each program and each programming
language into a single paradigm. That is emphatically not the case, however.
Paradigms overlap each other. Many are “sub-paradigms” of another paradigm; that is, they
are specific forms of some broader programming tradition. For that reason alone, a single
program can fall within multiple paradigms at the same time — and indeed most programs
do. What’s more, a single program may combine even disparate paradigms if its different
components are written in different ways.
Generally speaking, it doesn’t make too much sense to ask the yes/no question of whether
a specific program belongs to a specific paradigm. It may be more fruitful to consider
the extent to which a program is representative a paradigm.
Just knowing which language a program is written in is not enough to tell us which
paradigm(s) the authors have operated in. For example, Scala is designed to support
multiple programming paradigms and their combinations. In O1, we have written many
object-oriented programs, the majority of which are imperative but some of which are
largely or even purely in the functional style.
How do the paradigms differ, then? The answer is complex. Moreover, the answer is
complicated by the fact that there are no hard-and-fast definitions of each paradigm that
everyone would agree on; this chapter relies on the author’s interpretation. In any case,
this isn’t the place to even attempt a thorough analysis of all programming paradigms.
What we’ll do instead is consider two specific questions that elaborate on the above
diagram. Here they are:
How does object-oriented programming differ from other forms of
How does imperative programming differ from functional programming?
The yellow borders highlight the parts of the paradigm landscape
that we’re going to compare next.
The table below captures some of the essential features of object-oriented programming.
No objects; e.g., procedural programming
Entities in the program’s domain are modeled as objects.
Operations on those entities are modeled as methods on those
Operations are modeled as functions (that aren’t attached to
objects; objects are either not used at all or, if they are,
don’t play a major role in program design).
A program’s behavior is conceived of as communication between
objects that send messages to each other (thereby calling methods).
An object may delegate subtasks to other objects.
A program run happens by calling a “main function” that calls
other functions, which in turn call more functions.
Each object typically stores some information that it needs
while it runs its methods. objects may receive additional
information as method parameters. An object may also consult
another object for information.
The information that a function needs is passed in via the
Try imagining what our programs might look like if, after Week 1, we bypassed the concepts
of object, class, and method. Instead, we might have continued by constructing increasingly
complex programs from separate functions that call other functions. Had we done that, we
would have ended up doing imperative and/or functional programming without objects.
The table below lists some characteristics that, while not definitive of the object-oriented
paradigm, are commonly associated with it.
Data types are (often) represented as classes.
No concept of class, or classes play only a bit-part role in
Program design primarily seeks to identify the concepts
(classes and objects) of the problem domain and their methods.
Program design seeks to identify operations (functions) and the
data they operate on (parameters).
Programs and program design are often thought of as “noun-driven”,
since objects and classes commonly represent things that natural
language expresses as nouns.
Programs may be thought of as “verb-driven”, but there are
data-driven approaches to programming without objects, too.
Is arguably a natural way for humans to model the problem domain.
Conceptual modeling isn’t unique to OOP but the paradigm tends
to highlight it.
Is arguably a natural way for humans to model algorithms.
Emphasizes the principle of information hiding: objects/classes
each have their own areas of responsibility, and one cannot access
their private parts (implementation) from the outside. Information
hiding makes programs easier to understand and develop further.
Information hiding is not necessarily equally emphasized, but
this crucially depends on which specific approach is chosen
and on the programmer. The problems of global variables and
spaghetti code are often imputed to (bad) procedural programming.
Connected information is commonly stored in the instance
variables of an object.
Connected information is commonly stored in the variables of a
record (tietue; an object-like construct without methods)
or as a tuple.
Puts forward inheritance as a means of representing hierarchies
Common in both the academic world and the software industry.
O1’s official goals include teaching object-oriented programming, which shows in how the
course is designed. Apart from the “loose functions” of Week 1, most of our programs are
representative of OOP.
Declarative programming is a disputed and nebulous concept. We’ll gain more from comparing
imperative programming to a selected subparadigm of declarative programming than from an
attempted comparison of imperative programming with the entirety of declarative programming.
We’re about to compare the two paradigms framed in yellow.
The primary difference between imperative programming and functional programming
is their approach to representing state.
In an imperative program, executing an instruction in code may change the value of a
variable, pause to read user input, or cause another effect on program state that is
observable in the instructing code. Executing an instruction can impact on how subsequent
instructions mutate the program’s state.
In contrast, in a (pure) functional program, the program code consists of definitions
that don’t have observable effects on state in this sense: there are no “side
effects”. For instance, once a variable’s value is set, it never changes.
The table below elaborates on this key difference.
(Pure) functional programming
It is possible and acceptable to write functions that directly
modify the state information stored by the program; for instance,
an object may have a method that modifies the values of its
instance variables. A function’s return value may depend on —
not only which parameters you pass in — but also the program’s
Functions are effect-free. They don’t change the values of
existing variables. Given a particular set of values as
parameters, a function will always return the same value. The
state of an existing object is never changed; if you want an
object to represent a different state, you create a new object.
In other words, data structures such as objects may be mutable.
Data structures such as objects are always immutable.
Domains that feature state changes can be modeled in a
straightforward and highly intuitive fashion (e.g., the balance
of a bank account)
Domains that feature state changes can certainly be modeled;
a typical approach is to represent different states explicitly.
For instance, to represent the different states of a bank
account after each deposition and withdrawal, you may create
new objects that represent those changed states.
The programmer calls subprograms not only to obtain return
values but also to cause effects on state.
For instance, myAccount.withdraw(1000) mutates the state of
an account object. Even if you already know that method call
will return 500, it makes a difference if your code says val
received = 500 or val received = myAccount.withdraw(1000).
received = 500
val received = myAccount.withdraw(1000)
Each repeated invocation of a method may impact on the account
object’s state, and it is significant how many times you call
such a method on an object.
The programmer calls subprograms (only) to obtain their return
values. Assuming you know what a subprogram returns, you don’t
even need to call it. Any expression in the program can, in
principle, be replaced by another expression that evaluates to
the same value, without changing what the program accomplishes.
(That principle is known as referential transparency.)
For instance, if the function call computeResult(10) returns
123, you could just as well write 123 in the code.
As far as program correctness is concerned, it is irrelevant
how many times a particular function is invoked.
One practical difference in Scala programming is that the pure functional style uses only
vals, never vars.
Functional programming is often practiced in impure forms. For example, one might write
most of an application in a purely functional style, but implement the user interface in
an imperative style.
Referential transparency and “effects”
As indicated in the table above, one of the key principles of
functional programming is that you may substitute an expression’s
value for the expression itself without changing the program’s
meaning. What exactly does it take to follow this principle?
First, the principle implies that any expression must evaluate to
the same value every time. And in particular: each invocation of a
function on the same parameter values must invariably produce the
same return value. As an example, max(a, b) follows this rule
but Random.nextInt(10) doesn’t, nor does myCounter.value.
Second, evaluating an expression must not cause any effects that
you can externally observe and that are meaningful in terms of
what the program does. For instance, n = n + 1 observably changes
the variable’s value and println("Ave") observably changes the
n = n + 1
But “meaningful in terms of what the program does” sounds vague.
What counts as meaningful?
That’s something for the programmer to decide, and we already did
something of that sort early in O1: in Chapters 1.6 and 1.7, we
specified that changes to an object’s state and printing of textual
output count as meaningful effects but the passing of time while a
function runs doesn’t, nor does receiving a return value; this
delineation is a common one. Other factors that we have chosen to
ignore as effects include the allocation of memory for new objects
and the fact that the computer consumes electrical energy as it
executes our programs. In some other contexts, it can make sense to
consider those effects significant, too.
The meaningfulness of effects, then, depends on your goals and your
point of view. A good rule of thumb is this: an effect is meaningful in
case whether or not it happens affects whether or not you can consider
your program to work correctly.
For further information, take a look at online forums
and the book Functional Programming in Scala (see Books
and Other Resources).
Terminological note about “effects”
“Effects” in the sense we use the term here and elsewhere in O1 are
often called “side effects” in other contexts.
If you read other sources that discuss pure functional programming,
you may find people using the word “effect” differently, in
a sense that is not synonymous with “side effect”. See, e.g.,
“What do “effect” and “effectful” mean in functional programming?”.
This chapter may have given the impression that a purely functional
program can’t interact with its user.
It’s true that there are programs that are otherwise functional
but do I/O imperatively. However, there are tools for functional
I/O as well. As a challenging and voluntary activity, look up this
What is the role of functions in programming? What is the preferred way to repeat
commands in a program? Traditionally, different paradigms have leaned towards different
Subprograms and the data they operate on are often thought of
as separate things. On the one hand, there are methods/functions
that implement operations; on the other hand, there is data
stored as values in variables.
Functions are seen as a significant and common form of data.
It is common to write and use higher-order functions: functions
that take functions as parameters or that return functions.
(This is part of the reason why the paradigm is called “functional”.)
The primary means of repetition is iteration with a looping
construct. Loops modify program state. Effectful for–do
loops (Chapter 5.5) are representative of imperative
programming, as are while loops (Chapter 9.1).
Higher-order functions such as map, filter, takeWhile,
and foldLeft are in common use; such functions can be used to
achieve repetition without affecting program state. Alternative
means of repetition include generator expressions (not covered
in O1) and recursion (Chapter 12.2). while loops aren’t used,
as they serve no purpose if “side effects” on program state are
As noted above, imperative programs tend to make less use of higher-order functions,
but that doesn’t mean that such functions are unique to functional programming or
that imperative programs never feature them. Programming paradigms are not purely
technical constructs but cultural, too: the difference is that it’s customary do
things differently in different paradigms.
O1 primarily teaches imperative object-oriented programming; many of the programs in
this ebook feature mutable state. However, the course is designed to also give you a
taste of functional programming, a paradigm that features more prominently still in O1’s
follow-on courses. In particular, the way we’ve used higher-order methods to work on
collections since Chapter 6.3 is typical of functional programming.
Let’s take a look at a few familiar programs and see if we can spot any distinctive
paradigmatic features in them.
class Counter(var value: Int):
def advance() =
this.value = this.value + 1
override def toString = "value " + this.value
The counter class from Chapter 3.1 is an example of imperative OOP. We have a var;
the advance method has a “side effect” on program state; Counter objects are mutable.
Further representatives of the imperative style include (among many others):
Scala’s Buffer class. The state of a buffer changes when
elements are replaced, added, or removed.
The class o1.Grid: you can mutate a grid’s state by replacing
its contents at a particular GridPos.
The GUI class o1.View is designed so that a View object is a
view of a single mutable object that serves as the domain model
and whose state is changed by the view’s event handlers.
In Chapter 2.5, we sketched out the Pos class. Here’s some of its code:
class Pos(val x: Double, val y: Double):
def description = "(" + this.x + "," + this.y + ")"
def add(dx: Double, dy: Double) = Pos(this.x + dx, this.y + dy)
Pos objects are immutable: all their variables are vals that point to immutable
objects. When you compute, with add, a new Pos relative to an existing one, you
don’t change the original object but create and return a new Pos.
o1.Pic objects are similarly immutable. Their methods don’t
modify the original image but generate a new one.
The methods in class Odds (Chapter 2.5) also follow this
A Vector is an immutable collection (Chapter 4.2).
The GameState class of the Peeveli game (Chapter 10.2) is
Another example of the functional style is the standard String class. No String
object ever changes after being created; for instance, when you concatenate strings
with text1 + test2, you get an entirely new, longer string and leave the originals
as they were.
text1 + test2
This may be a good place to mention that Scala does have an alternative representation
for strings: the class StringBuilder is an “imperative version of String”. Its
instances are mutable strings:
val text = StringBuilder("man")text: StringBuilder = man
text.append("bear")text: StringBuilder = manbear
text.append("pig")text: StringBuilder = manbearpig
String is usually the more convenient choice, but StringBuilder is useful when
you want your program to concatenate a huge number of strings and need to optimize the
program’s efficiency. With StringBuilder, the computer doesn’t have to create as
many separate objects or collect that many unneeded objects as garbage.
The manner in which a class is designed and the manner in which that class is used
in a program are two separate things. For example, even though the design of the String
type represents the functional style of programming, it’s still possible to use the
class in imperative code:
var text = "cat"
text = text + "fish" // change in a var; this code is imperative in nature
It’s also perfectly possible to write an imperative-style implementation for a class that
provides a functional-style interface to its users. For example, a method in the class
might be implemented using local vars, despite the class’s instances being immutable.
Mini-assignment: from imperative to functional
Especially if you feel unsure about why we just classified some code
as imperative and some as functional, you may wish to do the following
short assignment where you take some familiar imperative code and
reimplement it in the functional style.
There’s an alternative way to write the Match class from Chapter 4.4:
let’s say a Match instance doesn’t represent the gradually changing
state of a football match, as before; instead, we’ll have it represent
a single, unchanging snapshot of a match’s state. Adding a goal to a
match will no longer modify an existing Match object; it will instead
create a new Match object that captures the new state.
Implement such a functional-style Match class. The details are in
Scaladoc form within module Football4.
(For this assignment, we’ve chosen a class that is quite easy
to reimplement as functional. Translating between paradigms is not
always as straightforward.)
Instructions and hints
Make sure that addGoal no longer returns Unit.
As stated in the docs, the Match class demands a constructor
parameter that indicates the scorers up until the present point
of time. For that purpose, the class uses an immutable collection;
a Vector works fine. When you create a new match state object,
you’ll need to construct a new vector that contains all the earlier
scorers plus the new one at the end. For that, you can use the :+
operator, which works as shown below.
val numbers = Vector(5, 1, 2)numbers: Vector[Int] = Vector(5, 1, 2)
val longerVector = numbers :+ 10longerVector: Vector[Int] = Vector(5, 1, 2, 10)
A+ presents the exercise submission form here.
The table below lists some more features that are typical of functional and imperative
programming. They all connect in one way or another to the key difference identified
Programs and subprograms (such as methods) are seen as
sequences of commands. Commands can directly affect program
Subprograms are seen as being akin to mathematical functions.
They simply return a value as appropriate for the given
parameters. (This is part of the reason why the paradigm is
known as “functional”.)
Typical collections include arrays (Chapter 12.1) and buffers,
which are mutable.
Values are stored in immutable collections. These include
vectors (Chapter 4.2), lists, and lazy-lists (7.2);
terminology varies greatly between languages, though.
When reasoning about a program, one must be alert for
state changes that happen behind the scenes and one must
pay particular attention to the sequencing of commands. For
instance, these commands:
val a = myObj.doStuff()
val b = myObj.doOtherStuff()
may produce different values than these ones:
This is because the methods can have effects on state.
It is often simpler to reason about programs. In many contexts,
execution order becomes a secondary concern. For instance,
val a = myObj.thing
val b = myObj.anotherThing
will always produce the same values as these ones:
This is because there are no mutations of state.
As another example, the behavior of myFunc(myObj.doStuff(),
myObj.doOtherStuff()) may crucially depend on the left-hand
parameter being evaluated first.
In myFunc(myObj.thing, myObj.anotherThing), it is generally
irrelevant which of the two parameter expressions is evaluated
The concept of reference (or memory pointer) is central to
reasoning about programs. References influence how expressions
change in value at different points of a program run. If multiple
variables refer to the same object, an effect on that object
through one variable will affect the use of all the other
variables as well (see, e.g., Chapter 1.5).
References are not as important, which simplifies things. Since
evaluating expressions doesn’t have effects on other expressions,
it cannot happen that a state-change via one variable affects
the use of another variable.
Historically, imperative implementations of programs have often been more efficient than
functional implementations. The imperative approach makes certain resource optimizations
But efficient implementations of functional programming do exist, too; real-world
efficiency depends on the program and the toolkit being used. These days, in the age of
multi-core processing and cluster
computing, the fact that functional
programs can be flexibly parallelized is very significant: since function calls don’t
affect state and since the evaluation order of expressions is relatively free in functional
programs, multiple processor cores can evaluate multiple expressions simultaneously.
Functional programs can thus be parallelized for substantial performance gains; this is
something that Programming 2 will discuss.
Imperative code is — proponents claim — easier to read than functional code is. The
code of a program directly expresses the steps of a program run.
Functional program code is — proponents claim — easier to read than imperative code
is. Functional programs are arguably easier to rid of bugs and develop further. Debuggers
and similar tools are perhaps not needed as often.
Many of the benefits of functional programming arise from how it is customary to write a
lot of small, effect-free functions and use them in combination. Such functions are easier
to reason about and easier to test in isolation, as the programmer doesn’t need to consider
effects on state and their potentially complex interactions. From such carefully designed
pieces, expert programmers can build demanding, fault-free systems for real-world use.
One last table. This one takes a look at the cultures and ways of thinking that have
evolved around the two paradigms.
Computer programming is perceived as commanding the computer:
“I tell the machine what to do.” Commands take the form of
consecutive statements in a programming language. These
statements describe, in order, what the computer should do.
Computer programming may be perceived as the description of
solutions: “I’ll give the computer a precise definition of
what I’m trying to achieve.” Comparatively speaking, a program
run is a roundabout consequence of the computer working to
achieve the described goals. (This is considered characteristic
of the declarative paradigm in general.)
The programmer may work on a low level of abstraction: the
program’s structure may bear a relatively close resemblance to
machine code and what goes on in the computer as it runs the
program (although the degree of that resemblance depends greatly
on the programming language, among other things).
The level of abstraction is high: programs are far removed from
Programming is often viewed as a branch of engineering.
Some proponents view programming as a branch of mathematics.
Is arguably a more natural way for humans to solve problems and
easier to learn.
Object-oriented programming is traditionally often combined with
Object-oriented programming is only sometimes — but
increasingly — used in combination with it.
Historically dominant in the software industry and among
hobbyist programmers. Also popular in the academic world.
Historically less popular in the industry, but there has been
a surge in popularity since the 2010s. Popular in the academic
Below, you’ll find four different implementations for the same functionality: simple
“storages” that each contain a certain amount of a specified substance. Compare
the implementations. Can you spot some typical characteristics of the different
programming paradigms that we’ve discussed?
class Storage(val substance: String, val capacity: Int, initialAmount: Int):
private var storedAmount = initialAmount
def freeSpace = this.capacity - this.storedAmount
def add(amount: Int) =
this.storedAmount = min(this.storedAmount + amount, this.capacity)
// ... other methods ...
val barrel = Storage("milk", 1000, 50)
val stillFree = barrel.freeSpace
class Storage(val substance: String, val capacity: Int, val storedAmount: Int):
def freeSpace = this.capacity - this.storedAmount
def add(amount: Int) =
Storage(this.substance, this.capacity, min(this.storedAmount + amount, this.capacity))
// ... other methods ...
val barrelState = Storage("milk", 1000, 50)
val newState = barrelState.add(500)
val stillFree = newState.freeSpace
class Storage(val substance: String, val capacity: Int, var storedAmount: Int)
// No methods. A storage is a record formed by the three variables defined just above.
def add(target: Storage, amount: Int) =
target.storedAmount = min(target.storedAmount + amount, target.capacity)
def freeSpace(Storage: Storage) = Storage.capacity - Storage.storedAmount
// ... other functions ...
val barrel = Storage("milk", 1000, 50)
val stillFree = freeSpace(barrel)
class Storage(val substance: String, val capacity: Int, val storedAmount: Int)
def add(target: Storage, amount: Int) =
Storage(target.substance, target.capacity, min(target.storedAmount + amount, target.capacity))
def freeSpace(Storage: Storage) = Storage.capacity - Storage.storedAmount
// ... other functions ...
val barrelState = Storage("milk", 1000, 50)
val newState = add(barrelState, 500)
val stillFree = freeSpace(newState)
Which two of the four implementations best represent object-oriented programming?
Two of the four implementations clearly have features of imperative programming. Which two?
Two of the four implementations are compatible with the tenets of the functional paradigm. Which two?
Which of the four implementations is the closest match with procedural programming?
Java is an imperative object-oriented
programming language. The latest versions of
Java provide some support for a more functional
style of programming.
Pascal is/was a programming language designed
for education whose heyday was in the 1980s and
1990s. It primarily represents the procedural
The C language is meant for procedural
programming. Its derivative C++ is mostly
used for either prodedural programming or
Python is a multi-paradigm language. Often,
people use it for imperative programming, but
you can program functionally in Python, too.
The language has support for objects; some
use it for OOP while others program in a more
In principle, nearly any language can be used for programming within
nearly any paradigm. Even though the language itself might not have
a particular feature — such as objects — the programmer may
strive for a programming style that emulates that feature. Moreover,
there are libraries that support unconventional styles of programming
in a particular language. Nevertheless, adopting a programming style
that runs counter to the language’s design is often inconvenient and
consequently rare. Some languages are a better fit for some paradigms
Isn’t Scala known as a functional programming language?
Yes, that too. Scala is a multi-paradigm language that is designed to
support several styles of programming. What is unusual about Scala is
the seamless amalgamation of object-oriented and functional programming:
you could say the language and its libraries tempt the programmer
towards an “object-functional” style and especially support this
combination of paradigms.
Scala’s advocacy of certain programming practices is reflected in
various details. One small example is the way the immutable (functional)
collection type Vector is available by default but the mutable
(imperative) Buffer needs an import.
There are quite a few programmers who use Scala for pure or near-pure
As said, many of our programs in O1 haven’t been in the functional
style. On the other hand, we have created various immutable classes
and made ample use of effect-free higher-order methods, which are
integral to functional programming.
Antiquating current paradigms
The beginning of the chapter suggested that even though the
well-known paradigms are worth learning about, they might be on the
verge of becoming obsolete. That is in part because of the rise of
“multi-paradigm” languages, as discussed above. If this theme tickles
your fancy, you could take a look at Joshua Gross’s brief commentary
on Quora, and of course there’s plenty more to be found on the web.
In many programmers’ minds and words, the field of programming is
divided in paradigms. A programming paradigm is a way of practicing
and thinking about programming.
Programming paradigms overlap with each other. They have no
unambiguous or universally accepted definitions. A programmer
may draw on multiple paradigms even within a single program.
Many people perceive there to be a major paradigmatic fault line
between imperative and declarative programming:
In imperative programming, the programmer
issues sequences of effectful instructions
to command the computer. Procedural
programming and the most common flavors of
OOP are forms of imperative programming.
In declarative programming, the programmer
focuses on describing the relationships
between parts of a solution rather than
the ordering of sequential commands.
In O1, we practice object-oriented programming. We often combine it
with the imperative style but draw on functional programming as well.
Functional programming is a well-known
form of declarative programming.
It’s possible to write object-oriented
programs, too, in a functional style.
Scala, as a language, encourages this.
The most fundamental difference between functional and imperative
programming is that in (pure) functional programming, all data is
immutable and all functions are effect-free and independent of
Another difference of note is that in
functional programming, it is especially
common to pass functions as parameters
to other functions.
The higher-order methods from previous
chapters (map, filter, etc.) are
typical of the functional paradigm.
Different paradigms have their own strengths and weaknesses. In the
future, the divides between the paradigms may grow less steep. Keep
an open mind as you build your expertise as a programmer. Don’t
fall victim to dogma!
Links to the glossary: programming paradigm, object-oriented programming,
imperative programming, functional programming, procedural programming;
mutable, immutable, effectful function, effect-free function.
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 the lab sessions
or Piazza. We can’t guarantee that anyone will even see anything
you type here before the weekly deadline.)
The additional questions below concern the past O1 Week (whose last
chapter this is) as a whole. Answering these questions is not mandatory,
but we hope that you do. In any case, please remember to submit this
form; the button is down there.
Your answers will be accessible by the course staff. We’ll combine the
answers of all O1 students to compute (anonymous) statistics that will help
us improve the course and to research programming education. We are grateful
for your patience in answering these questions!
The past Week of O1 (i.e., the chapters with their assignments) was fun to do.
1 — not at all true
7 — completely true
no answer / skip question
I would describe the past Week as very interesting.
I felt pressured while doing the past Week.
During the Week, I felt that I wanted to learn more about the topic.
I had to force myself to do this Week’s activities.
I did not feel nervous at all while doing the past Week.
I thought the past Week was boring.
I felt very tense while doing the past Week.
I thought the past Week was quite enjoyable.
While I was working on the past Week, I was thinking about how much I enjoyed it.
The contents of the Week felt exciting.
I was very relaxed in doing the past Week.
The past Week did not hold my attention at all.
During this Week, I did some tasks in order to avoid feeling badly about myself.
I very much enjoyed O1 during the past Week.
I was anxious while working on the past Week.
Comparing the past Week of O1 to my other studies, I’ve been feeling...
1 — much less pressure from O1 than from other courses
4 — equal pressure from O1 and other courses
7 — much more pressure from O1 than from other courses
Comparing the past Week of O1 to my other studies, I’ve been...
1 — much less stressed about O1 than about other courses
4 — equally stressed about O1 and other courses
7 — much more stressed about O1 than about other courses
During the past Week, I felt interested in my other, non-O1 studies (regardless of what I thought of O1).
I enjoyed the past Week of O1 more than I enjoyed my other studies during the same time.
I think that the past Week of O1 is useful for learning to program.
I think the past Week is important to do because it helps students learn programming.
I could not do the past Week’s activities very well.
I generally understood what I was expected to do during the Week.
I think that the past Week’s activities can help me improve my programming skills.
I believe the past Week’s studies could be beneficial to me.
If I study in appropriate ways, then I will be able to learn the material in this course.
It is my own fault if I don’t learn the material in this course.
I think I was pretty good at the past Week’s O1 activities.
I think I did pretty well in the past Week, compared to other students.
I think the past Week is an important activity.
I was pretty skilled at the past Week’s activities.
I would be willing to do an activity such as this Week again, because this sort of learning has some value to me.
The contents of the past Week felt difficult.
If I try hard enough, then I will understand the course material.
If I don’t understand the course material, it is because I didn’t try hard enough.
After working at the past Week’s activities for a while, I felt pretty competent.
I am satisfied with my performance in O1 during the past Week.
I believe the past Week’s activities could be of some value to me.
Comparing the skills I used in O1 during this Week to the skills I need in other courses that I’m taking, I feel that I am...
1 — definitely less skilled in O1’s topics than other studies
4 — equally skilled in O1 and other studies
7 — definitely more skilled in O1’s topics than other studies
Comparing my accomplishments in the past Week of O1 to other courses that I’m taking, I feel that I am...
1 — definitely performing less well in O1 than in other studies
4 — performing equally in O1 and other studies
7 — definitely performing better in O1 than in other studies
Thousands of students have given feedback and so contributed to this ebook’s design.
The ebook’s chapters, programming assignments, and weekly bulletins have been written in
Finnish and translated into English by Juha Sorva.
The appendices (glossary, Scala reference,
FAQ, etc.) are by Juha Sorva unless otherwise specified on the page.
The automatic assessment of the assignments has been developed by: (in alphabetical order)
Riku Autio, Nikolas Drosdek, Joonatan Honkamaa, Antti Immonen, Jaakko Kantojärvi, Niklas
Kröger, Kalle Laitinen, Teemu Lehtinen, Jaakko Nakaza, Strasdosky Otewa, Timi Seppälä,
Teemu Sirkiä, Anna Valldeoriola Cardó, and Aleksi Vartiainen.
The illustrations at the top of each chapter, and the similar drawings elsewhere in the
ebook, are the work of Christina Lassheikki.
The animations that detail the execution Scala programs have been designed by Juha
Sorva and Teemu Sirkiä. Teemu Sirkiä and Riku Autio did the technical implementation,
relying on Teemu’s Jsvee and Kelmu toolkits.
The other diagrams and interactive presentations in the ebook are by Juha Sorva.
The O1Library software
has been developed by Aleksi Lukkarinen and Juha Sorva. Several of its key components
are built upon Aleksi’s SMCL
The pedagogy of using O1Library for simple graphical programming (such as Pic) is
inspired by the textbooks How to Design Programs by Flatt, Felleisen, Findler, and
Krishnamurthi and Picturing Programs by Stephen Bloch.
The course platform A+ was originally created at Aalto’s LeTech
research group as a student project. The open-source project
is now shepherded by the Computer Science department’s edu-tech team and hosted by the department’s IT
Markku Riekkinen is the current lead developer; dozens of Aalto students and others have also contributed.
The A+ Courses plugin,
which supports A+ and O1 in IntelliJ IDEA, is another open-source project. It has been designed and
implemented by various students
in collaboration with O1’s teachers.
For O1’s current teaching staff, please see Chapter 1.1.
Additional credits appear at the ends of some chapters.