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 does Scala work? What sorts of things
does Eclipse do for me behind the scenes? Why do some arithmetic
operations work all funny?
Topics: Representing data as (binary) numbers. File formats.
Compilers, virtual machines, bytecode, and machine language.
Garbage collection. Restrictions on numeric data types. Scala
tools at the command line.
What Will I Do? Mostly read. A few mini-assignments.
Rough Estimate of Workload:? One hour.
Points Available: A5.
Related Projects: None.
We’ll now take a break from learning to instruct the computer in new ways. In this chapter,
we’ll instead investigate the different stages that a program goes through on its way to
becoming a concrete program run.
Let’s get started with this short presentation:
The illustrations in this chapter pay tribute to a classic book (Finnish
An IDE such as Eclipse takes care of these stages automatically and often unnoticeably.
Eclipse, too, uses numerous individual tools such as a compiler and a virtual machine;
it’s just that their integration into the Eclipse platform is seamless enough that
the IDE’s user often doesn’t need to think (or even know) about the fact that they are
actually using multiple auxiliary programs. So far in O1, we’ve let Eclipse work its
magic. But now we’ll take a peek under the hood.
If Eclipse does things automatically for us, is there any call for this chapter?
Well, yes. For starters, a program can be viewed at different levels of abstraction. The
execution of an object-oriented program, for example, can be described in highly abstract
terms as communication among objects. That high level of abstraction is founded on a lower
level where the program is a sequence of instructions in a programming language. At a lower
level still, the execution of those commands involves operations on bits within a computer’s
Even as you work at a particular level of abstraction, it’s helpful to understand the
basic principles of the level beneath. The ability to peer inside an abstraction is
particularly useful when your instructions to the computer fail to do what you intended
or expected them to do.
The same goes for the auxiliary programs that help us program. Even if you use an IDE, it
pays off to have at least a passing understanding of how it works.
A second good reason for this chapter is that in the “real world” outside O1, Eclipse
is hardly the only tool that people use for programming. It makes sense to know the
basic principles behind our toolkit so that you’ll find it easier to adapt to similar but
Another reason is that much of what we’re about to discuss would be considered by many
to be the sort of general knowledge that any programmer or informed citizen should know.
And of course, some programmers need to be able to create Eclipses and the like for
themselves and other programmers to use. (But that’s not something we’ll get to in O1.)
So let’s take a look at the way Scala works.
It will be easier to appreciate the distinct stages of a Scala program if we leave the
comfort of our IDE for a while and use separate utilities instead.
The official Scala toolkit (from http://www.scala-lang.org/) contains a number of
In addition to scalac, many programmers use fsc (Fast Scala
Compiler) and sbt (Scala Build Tool). For more information on
these tool, look them up on the net.
The short presentation below demonstrates how to create and run a tiny Scala program
using a text editor, a compiler, and a virtual machine as separate programs.
Know the command line?
To follow the presentation below, it’s helpful if you have even a
passing familiarity with working at the command line — that
is, if you know how to enter textual commands in an environment
such as Windows’s Command Prompt or Linux’s terminal windows.
If you don’t, you may wish to look up a tutorial online. On the
other hand, you can probably appreciate the main points even
without such experience.
You should now have an inkling of how a Scala program is processed. The next sections
elaborate on the transformations and tools introduced above and link them to what
you’ve done so far in Eclipse.
Much of what’s coming up involves transformations of data within the computer, so you’ll
need to know something about how computers represent data. Let’s discuss bits.
A binary number consists of zeros and ones. A single binary digit — a single
zero or one — is called bit (bitti).
For instance, here are a couple of numbers in our usual (decimal) number system converted
14decimal = 8 + 4 + 2 = 1*23 + 1*22 + 1*21 + 0*20 = 1110binary
5decimal = 4 + 1 = 1*22 + 0*21 + 1*20 = 101binary
14decimal = 8 + 4 + 2 = 1*23 + 1*22 + 1*21 + 0*20 = 1110binary
5decimal = 4 + 1 = 1*22 + 0*21 + 1*20 = 101binary
Goodness gracious, what is a qubit?
If you want to rattle your brain, do an internet search for
quantum computers (kvanttitietokone) and find out how
they use qubits (kubitti) instead of bits.
A computer is a digital system. In its memory, all data is represented as binary numbers
or other sequences of bits.
A picture is made up of colored dots, pixels. The color of each pixel can be
expressed as numbers and those numbers can be expressed as bits.
Text is made up of characters; people may define how each different character uniquely
corresponds to a particular number. Scala strings follow a numbering scheme defined by the
Unicode standard (http://www.unicode.org/). Here are a few example characters and their
values in Unicode:
Knowing the number that matches a particular character, we can represent that character
as a binary sequence (one way or another; direct conversion into binary as illustrated
above is one option). Strings can then be represented as a sequences of such binary
You’re familiar with the concept of a reference by now: a reference is a small granule
of data that we can use to access some other data (an object). In this ebook’s animations,
you have seen references stored in variables and passed as parameters. At a lower level
of abstraction, those references, too, are binary sequences that — one way or another —
identify a specific location in computer memory that stores an object.
It’s not just the data that a program processes that gets stored as bits; the
program itself also consists of bits, usually stored in a file. In fact, the program
is data, too, and programs can process other programs!
In the case of Scala and most other programming languages, source code is stored as
so-called “plain text”, which consists of each character’s binary representations
and nothing more. The compiler takes in that data and produces an output that represents
the program in a different binary format.
Which brings us back to programming tools. Let’s first consider text editors and source
A “plain text” file — often called simply a text file — stores a sequence of bits.
Parts of that sequence correspond to numbers, which in turn correspond to characters as
defined by a standard. To read and edit such a file, you need an application that’s been
programmed to interpret the bits as characters. Such applications include, among many
others, Eclipse’s editor, Emacs, Notepad in Windows, and TextEdit on Macs.
Other file formats (e.g., spreadsheets, GIF image files, Word documents) store bits
according to different standards. To work on these files, you need an application that
can interpret binary sequences according to the logic of the particular file format.
See for yourself
If you want, you can open, say, a Word document in Notepad (or
some other non-plain-text file in an editor meant for plain-text
editing). The bits in the Word document don’t represent just
written characters but also font settings, other formatting instructions,
and metadata, which is why Notepad fails to interpret them correctly.
Oblivious to its shortcoming, the application takes in the bits and
interprets them as characters; a messy jumble of letters and special
characters appears in the editor.
You can write program code not just in Eclipse but in any application that lets you
edit and save text files. Notepad, for example, is a perfectly possible environment
for coding; it’s just that its other features don’t provide much if any support for
programming, so practically no-one wants to use it for that purpose. There are many
other text editors that aren’t part of an IDE but nevertheless have features that support
The files of Scala code that you edit in Eclipse get stored in the file system just like
the documents you save in other applications. The files are located in subfolders of your
Eclipse workspace folder.
Scala is a high-level language (korkean tason ohjelmointikieli). What that means
is that the language has a high level of abstraction and its expressions don’t directly
involve to low-level concepts like binary numbers or the physical components of a computer.
No ordinary computer has a processor that executes commands in Scala or any other
high-level language. A processor produces the program’s behavior by executing large
numbers of primitive instructions in machine language (or machine code;
An instruction in machine language is a sequence of bits that corresponds to some
low-level operation such as arithmetic on binary numbers, comparison between sequences
of bits, or switching zeros to ones. Different types of processors have their own
machine languages where different binary sequences correspond to different operations.
Programming in a machine language is laborious and error-prone. Creating a very large
software system directly in machine code is like building a real skyscraper from
Lego: practically impossible.
The source code that a programmer writes needs conversion into a form that the
computer can execute. Traditionally, programmers have tended to distinguish between
two ways of accomplishing this: To compile (kääntää) a program is to convert
it into executable form before one instructs the computer to run it. In contrast, to
interpret (tulkata) a program is to convert the program incrementally while it
is already being run.
The first step in processing a Scala program is compilation.
Compilation is a systematic (and rather complex) process that an auxiliary program,
a compler, can take care of. It yields code (so-called “binaries”) that are meant for
the machine to run. As it compiles a program, the compiler program also ensures in
advance that the source program follows the programming language’s syntax.
Eclipse is equipped with a compiler. On default settings, Eclipse’s Scala IDE compiles
Scala source code repeatedly and automatically while you edit the code. Many of the
error messages that you’ve seen are a product of these automatic compilations.
You’ll recall that several earlier chapters have mentioned compile-time-errors.
Many programming languages are usually compiled directly into a machine code; the
resulting machine-code program is then provided for end users to run. For example, the
.exe files that you may know from Windows contain machine code, usually produced
by compiling a program written in some high-level language. There is an alternative,
Using an intermediate language (välikieli) is an increasingly common alternative to
directly translating source into machine code. Here’s the basic idea:
Scala programs, for example, are (normally) first compile into an intermediate
Some intermediate languages go by the name of bytecode (tavukoodi); the
intermediate language used with Scala is one of them. The Scala compiler generates
so-called class files that contain bytecode. A single .scala source file compiles
into one or more .class files.
Locate your class files
Browse the contents of your O1 workspace folder through the operating
system. Inside the project folders, you’ll find subfolders named bin.
The name may sound like a garbage bin for deleted files, but it’s actually
short for “binaries”. These folders contain the compiled bytecode versions
of each project’s Scala source, stored in files with the .class suffix.
Bytecode consists of rather primitive instructions and resembles machine code. Like
machine code and unlike source code, bytecode isn’t meant primarily for humans to read
and edit. The class files that store the bytecode aren’t text files, and a plain-text
editor won’t display their contents properly.
A class file loaded into the Notepad editor,
which is fairly useless for examining the file.
To make use of bytecode files, you need a program that specializes in just that. The most
important of such programs is the virtual machine.
The word virtual (virtuaalinen) has many meanings, such as:
A virtual machine is a computer program that operates as though it was a computer without
actually being a physical computer.
When you select Run As ‣ Scala Application and tell Eclipse to run
your program, it looks as though Eclipse takes in your Scala code and runs it. Eclipse
itself does not in fact run your program, however; what it does is launch an auxiliary
program — a virtual machine that takes care of running your program. Eclipse gives the
virtual machine a bytecode version of the code you wrote and tells it where to start
executing the program (which depends on the app object you selected). In essence, what
Eclipse does is exactly what we did as we manually issued the command scala Ave on the
command line above.
The virtual machine that you’ve used is, in effect, a computer whose processor can execute
bytecode instructions; bytecode is that machine’s virtual machine language. The virtual
machine processes each bytecode instruction, works out which instructions in actual
machine code correspond to it, and passes that actual machine code to the physical computer.
In practice, what happens is that your program gets executed.
The virtual machine governs the program run. It sees to it that the bytecode instructions
are dealt with in the correct order and manages the program’s use of memory. In other words,
the virtual machine takes care of exactly the sorts of things that you’ve seen illustrated as
animated diagrams throughout this ebook: it allocates and deallocatres frames in the call
stack, creates objects in memory, and so forth.
Scala programs are usually run in a virtual machine called the JVM, which is short
for the Java Virtual Machine.
Isn’t Java the name of a completely different programming language?
Indeed it is, but we nevertheless run our Scala programs in the Java Virtual Machine.
The JVM is a program that runs programs that have been compiled into a specific bytecode
format. That bytecode format was originally created for use with the Java programming
language, which is why the virtual machine is known as the JVM. However, the JVM can run
any programs that have been compiled into the JVM’s bytecode, no matter which programming
language the source code was originally written in.
So we can perfectly well use the JVM to run Scala programs as long as we have a Scala
compiler that transforms our programs into .class files. Over the past couple of decades,
the JVM has become a popular platform for running programs written not only in Java but
newer and more advanced programming languages as well, Scala being one example.
The most widely used implementation of Scala, which we use in O1 also, is the one
that’s “built on top of Java”. The Scala libraries that we rely on have been implemented
using the manifold existing libraries written in Java. If you pay attention, you
can glimpse the underlying Java implementation here and there. Perhaps you’ve already
noticed some of the following.
All that being said, the Scala language isn’t dependent on Java as such. Alternative
implementations for the Scala libraries and tools can be made and have been made.
The most significant of these alternatives is Scala.js,
possible to run Scala programs in a web browser.
What are the benefits of first compiling to an intermediate language and then running the
program in virtual machine? Wouldn’t it be more straightforward just to compile directly
to machine code?
Let’s consider a few important criteria:
Virtual machines are more popular now than they were in the past, and the trend seems to
On actually running bytecode
Some unusual computer hardware has
been made that executes JVM bytecode “directly”. Most computers don’t, though,
so we use a virtual machine that translates the bytecode into machine code.
We sometimes create an object that we need for only a short while. For example, an object
might be used only while a single line of code is running. Consider the following code.
What happens to the buffer object after we’ve executed the print command?
println(Buffer(5, 2, 7, 32, 9)) // Note: we don't store a reference to the newly created buffer
// After the println, we might enter other commands that don't use the buffer.
Objects that have been abandoned in memory and are inaccessible to the program are
called garbage (roska). Garbage just takes up computer memory but no longer serves
So as not to waste memory resources, any memory allocated for garbage should be released
for other use while the program is still running. That doesn’t always happen, though.
A memory leak (muistivuoto) is a classic bug: a program allocates memory for its
needs but fails to release its hold on that memory after its done with it. Little by
little, a leaking program may end up reserving more memory than is available and crash
Some programming environments expect the programmer to issue explicit commands in order
to release memory that is no longer needed. Consider an example in the C++ programming
language. The first command below reserves memory for an object’s data and initializes a
new object. It looks quite a bit like Scala.
SomeClass* myObj = new SomeClass(); // This is C++, not Scala.
var myObj = new SomeClass // This is the corresponding command in Scala.
Once the object has served its purpose, the C++ programmer removes the object from
delete myObj; // This is C++, not Scala.
This prevents the unneeded object from cluttering up the computer’s memory.
We haven’t learned a Scala command that works like delete. There isn’t one.
If we have a long-running Scala program that keeps creating objects, will it also require
an ever-increasing amount of memory?
One of the jobs of the Java Virtual Machine is garbage collection (garbage collection).
The JVM automatically keeps track of which objects have become garbage and releases the memory
allocated to those objects. As programmers, we don’t have to deal with garbage directly.
The JVM considers an object to be garbage in case no references that point to it are stored
Automatic garbage collection eliminates most memory leaks. Even so, a Scala program isn’t
wholly immune to leakage. Consider this example: A program uses a buffer to store assorted
references to objects. As long as those references are stored in the buffer, JVM’s garbage
collector won’t release the memory that the objects take up, even if the program no longer
actually needs all the objects in the buffer for anything. However, if the buffer object itself
becomes garbage, and if the objects it stores aren’t stored anywhere else, then both the buffer
and its contents become garbage and will be automatically cleaned up. It’s up to the programmer
to design their program so that it stores references in variables or collections only while
the referenced objects have a purpose in the program.
How can I share my Scala app so that others can use it?
There are many alternative ways to do that. Below is a brief summary. The topic
will come up again in the spring course Programming Studio 2.
If the end user’s computer already has the Java Virtual Machine
and its associated libraries installed, a fairly simply option
is to pack your app into an executable JAR. An executable
JAR is a file that bundles together the compiled .class files
as well as the libraries that Scala needs. Within the JAR file,
you can also record which app object starts your program. SBT
(Simple Build Tool) is one of the tools that you can use to
bundle a Scala app in an executable JAR.
Scala.js is a relatively new toolkit
merit is that modern web browsers can run it as part of a web page.
Native compilers generate platform-specific machine code.
Such a compiled program may then be bundled with a library that
takes care of things like garbage collection. Even though Scala
isn’t usually compiled this way, there are tools for it:
A “Java wrapper” is a program that bundles a compiled Java or
Scala program together with a small helper program. When run,
the wrapper program either uses an existing JVM if available or,
failing that, installs the required software.
Java Web Start is a technique for creating web links that
launch the JVM. The Java Web Start tool helps the user install
the application and the JVM as needed before starting the app.
For more information on several of the alternatives listed above, see:
When reading up on these matters, note that — as stated in our glossary
— the word “Java” sometimes refers to the Java programming language
and sometimes to the JVM and associated technologies (the latter being
more relevant to us as Scala programmers). Authors aren’t always clear
on which one they’re talking about.
Last but not least, it’s worth mentioning that these days many applications
are provided to end users as a web applications whose internal logic runs in
a networked server while the user interface runs in the user’s web browser,
a client. When Scala is used for implementing the server side of things,
it suffices to install the appropriate tooling (the JVM, etc.) on the server
rather than the client. Web applications will be discussed further in O1’s
Is it possible to “un-compile” a compiled program back to source code?
In principle, yes. In practice, sort of.
When source code is compiled into machine language, some of the
information recorded in the source is generally lost. For instance,
variable names, comments, and other constructs that structure the
high-level program may be lost.
Depending on the original program, the programming language, and the
compiler, the code produced by a reverse compiler may be very difficult
for a human to make sense of. It is by no means guaranteed that the code
is easy enough to comprehend that reverse compilation is worth the
There are tools that purposely make it more difficult to recover
the source code from its compiled version.
Look these up: decompiler, reverse engineering, code obfuscation.
Open source (avoin lähdekoodi) is yet another term whose precise
meaning depends on who you’re talking to. Nevertheless, the core
meaning is that open source is about making the source code of a program
publically available and allowing people other than the original creator
to use it in their software projects.
Source code can be published under any of a number of open-source
licences. Those licences set different policies on whether
commercial use is allowed, whether the licencee must also publish
derivative work under the same licence, and so on.
Open source can be an asset when multiple parties — companies
and/or individuals — develop software in collaboration. An
open-source community can brainstorm ideas, implement them as code,
and jointly assess the work of community members to ensure better
Open source is also associated with values and ideologies, as discussed
There are at least hundreds of thousands of open-source projects;
the Linux operating system is probably the most famous one. Other
well-known examples of open source include the Firefox browser and
the Thunderbird email application, both developed by the Mozilla
Foundation, a non-profit organization that promotes openness. Eclipse
is another example. So is Scala.
Each page that describes a class in the Scala API documentation has a Source
link near the top. You can click it to take a look at that class’s
source code. Scala has been published under a highly permissive
Compilers vs. interpreters
Compilation and interpretation are separated by a line drawn in sand.
It’s not always easy — but perhaps not necessary, either — to say
if a tool is a compiler or an interpreter. Intermediate languages and
virtual machines further muddle the distinction, as does just-in-time
compilation or JIT (ajonaikainen kääntäminen). As an optional
reading assignment, look up the latter on the internet.
Some programming environments thoroughly interleave the writing of
source code, its compilation/interpretation, and its execution.
The Scala REPL is one such environment.
Exploring the JVM bytecode
(This optional assignment is best suited to readers who have programming
experience from before O1. This topic will be introduced in more detail in
You can use auxiliary programs named javap and scalap to examine
the bytecode instructions that a Scala program compiles to. Search online
to find out how to use these utilities, then use them to examine a compiled
Scala class of your choice.
More virtual machines
Find out what other virtual machines and intermediate languages exist apart
from the JVM and its bytecode. For example: find out what the CLR is and
languages in web browsers.
Think about the command println(2147483647 + 1) and the output
it produces. Then enter the command in the REPL. Did the output
match your expectations?
println(2147483647 + 1)
Enter the output you got here:
Think about the command println(100.0 / 11.0 * 11.0) and the
output it produces. Then enter the command in the REPL. Did the
output match your expectations?
println(100.0 / 11.0 * 11.0)
At the beginning of this chapter, we established that the computer stores numbers
and other data as bits. That’s something we don’t need to constantly think about as
programmers though. A Scala program is a high-level abstraction of a computer’s
internal behavior, and much of the time we can think about our programs at that
abstract level. However, even in Scala programs, bits do come into play sometimes.
The two print commands above are cases in point. Let’s see why their output is so odd.
Consider how many different values can be represented with a given number of bits:
For reasons of efficiency, Scala (like many other languages) specifies that a specific
number of bits — 32 to be precise — is used for storing each and every value of type
Int. The value of an Int variable invariably takes up 32 bits of memory. Put
differently, an Int takes up four bytes (tavu) of memory; one byte equals eight
32 bits is enough for 232 different combinations of zeros and ones.
This means that there are 232 different values of type Int —
a constant, finite number of bits simply isn’t enough to represent an infinite number
of different integers.
The Scala language specification states the 232 values are the integers
in this interval:
-2147483648 ... +2147483647
-231 ... +231-1
-2147483648 ... +2147483647
-231 ... +231-1
The compiler does not check that the integers you use in your programs “fit” the data
type, and neither does the virtual machine. It’s your job as a programmer to make sure
you don’t attempt to represent numbers outside that interval as Ints.
Computing with numbers that are too large or too small can yield some unexpected results,
as in 2147483647 + 1. As you can see, the first operand in our example wasn’t chosen
at random: it is precisely the largest integer that fits the Int type. Adding one more
causes the result to “wrap around”.
2147483647 + 1
The pros don’t always get it right, either
The limitations of numeric data types can impinge on user experience
unless the programmer is aware to them. Former O1 students have spotted
this in games:
In 2014, Gangnam Style broke YouTube:
“The music video for South Korean singer Psy’s Gangnam Style exceeded YouTube's view
limit, prompting the site to upgrade its counter. YouTube’s counter previously
used a 32-bit integer [which] means the maximum possible views it could count
The failed launch of the spacecraft 1996 Cluster in 1996 is an example of a
more serious incident. Wikipedia reports:
“[The launch] ended in failure due to an error in the software
design [which] caused inadequate protection from integer overflow.
This resulted in the rocket veering off its flight path 37 seconds
after launch, beginning to disintegrate under high aerodynamic
forces, and finally self-destructing by its automated flight
termination system. The failure has become known as one of the
most infamous and expensive software bugs in history. The failure
resulted in a loss of more than US$370 million.”
If you have a fear of flying, keep your eyes closed for this paragraph. Because in
2015, it came out that the electricity in the Boeing 787 Dreamliner would switch off
unless the plane was “rebooted” at least every 248 days.
“What’s 248 days in other time units?”, one wonders.
Sometimes, an oversight such as this becomes a data-security issue.
Scala allocates eight bytes, or 64 bits, to every Double. It uses those 64 bits to
represent each Double as a so-called floating-point number (liukuluku; Double
comes from “double-precision floating-point number”). The floating-point format consists
of a sign bit (“plus or minus”), a multiplier known as the mantissa, and an exponent.
The details of the format are unimportant for present purposes (but you can easily find
them on the internet if you’re interested). For us, the significant thing is that since
the available memory is finite, it’s impossible to represent a decimal number of arbitrary
precision as a Double. The number of bits allocated for each Double constrains the
data type’s magnitude and precision. 64 bits is enough to reach a precision of roughly
fifteen significant digits.
Since Doubles aren’t stored to an arbitrary precision, computing with Doubles
often yields “inexact” results such as the one you got when you evaluated 100.0 / 11.0 * 11.0.
The division doesn’t produce an “infinitely precise” result; multiplying the approximate result
by eleven gives only something close to a hundred.
100.0 / 11.0 * 11.0
Here’s another example:
2.999999999999999res0: Double = 2.999999999999999
2.9999999999999999res1: Double = 3.0
Due to finite precision, it’s rarely meaningful to use the == operator to compare
The phenomenon has some odd-looking consequences. Let’s try rounding a couple of
numbers to the nearest integer:
5.499999999999999.roundres2: Long = 5
5.4999999999999999.roundres3: Long = 6
The second Double literal actually stands for the number 5.5, which rounds upwards.
But what does Long mean in the REPL’s output?
Int and Double are the most common numeric types in Scala. But they aren’t the best
fit for all situations, so there are alternatives available. It’s up to the programmer
to use types that are “large enough” to fit whichever numbers the program needs. Moreover,
it occasionally pays off to optimize resources by choosing types that take up fewer bits
of memory than Ints and Doubles do.
A need for Long?
In Stars, we stored each star’s Henry Draper number
in an id variable of type Int. Since our program was concerned
with visible stars only, the Int type was more than adequate.
If our needs had been more astronomical, we might have reached the
limits of what Int can cope with.
In O1, you’ll be fine using Ints for integers and Doubles for “decimal numbers”.
You can look up the other types online if you’re interested.
It already came up that each pixel of an image can be represented as numbers that define
the pixel’s exact hue.
One common representation is the RGB model, which defines each color in terms of
its red, green, and blue components. Each component is a number. The range of those
numbers depends on how many different colors are available. A range of zero to 255 is
The familiar Color type you know from the o1 package uses exactly such an RGB
representation for colors. This is easy to observe:
Thus far, we’ve used only color constants like Red and LightBlue. You can
also create an object that represents a specific hue:
val preciselyTheColorWeWant = Color(220, 150, 220)preciselyTheColorWeWant: Color = Color(220, 150, 220)
Every Color object has the variables red, green, and blue:
preciselyTheColorWeWant.redres4: Int = 220
preciselyTheColorWeWant.greenres5: Int = 150
The constant colors that you’ve used also have the same variables; see for yourself.
Find out the component values of White, Black, and Brown, for example.
How much red is there in Brown?
Pic objects have a pixelColor method that you can call to get the color of a
specific pixel: myPic.pixelColor(x, y). Try it.
How much red is there in the pixel that appears at (100,100) within Pic("defense.png")?
More on colors
There are other things you can do with a Color object, too. Here are a
couple of examples; the documentation lists more methods.
It’s easy to generate a slightly darker or lighter version of a color:
val slightlyLighter = Brown.lighterslightlyLighter: Color = Color(174, 64, 64)
val somewhatDarker = Brown.darker.darkersomewhatDarker: Color = Color(133, 33, 33)
val testPic = rectangle(100, 100, Brown).leftOf(rectangle(100, 100, slightlyLighter))
.leftOf(rectangle(100, 100, somewhatDarker))testPic: Pic = combined pic
In addition to their R, G, and B components, colors have an opacity value (sometimes
called the alpha channel):
Blue.opacityres6: Int = 255
val translucentRed = Color(255, 0, 0, 100)translucentRed: Color = Color(255, 0, 0, 100)
rectangle(300, 100, translucentRed).onto(circle(200, Blue)).show()
In this chapter, you’ve seen but a tiny fraction of the vast conceptual and technological
landscape around virtual machines, compilers, machine language, and bits and bytes. In
follow-on courses, you’ll get to explore farther and delve deeper. If you’re champing at
the bit, go ahead and take an advance look at CS-A1120 Programming 2.
Here’s one more:
0.1 + 0.1 + 0.1res7: Double = 0.30000000000000004
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.
Additional credits appear at the ends of some chapters.