The latest instance of the course can be found at: O1: 2024
Luet oppimateriaalin englanninkielistä versiota. Mainitsit kuitenkin taustakyselyssä osaavasi suomea. Siksi suosittelemme, että käytät suomenkielistä versiota, joka on testatumpi ja hieman laajempi ja muutenkin mukava.
Suomenkielinen materiaali kyllä esittelee englanninkielisetkin termit. Myös suomenkielisessä materiaalissa käytetään ohjelmien koodissa englanninkielisiä nimiä kurssin alkupään johdantoesimerkkejä lukuunottamatta.
Voit vaihtaa kieltä A+:n valikon yläreunassa olevasta painikkeesta. Tai tästä: Vaihda suomeksi.
Chapter 2.7: A Complete Scala Application
About This Page
Questions Answered: How do I write and store an entire Scala program? Where does a Scala application’s execution begin? How can I read input from the user’s keyboard? Now that I’ve created a conceptual model of a game world, how can I define a GUI that displays the world?
Topics: App
objects. Keyboard input with readLine
. The basics
of graphical user interfaces with o1.View
.
What Will I Do? Mostly program, guided by the text.
Rough Estimate of Workload:? Two hours.
Points Available: A75.
Related Modules: Ave (which we’ll create from scratch), Odds, IntroApps (new), FlappyBug.
Introduction
You have created objects. You have called their methods in the REPL, an environment that is well suited for experimentation.
However, the commands that you’ve entered in the REPL don’t form a unified whole that is stored for later use, that can be lauched again at will, that can be readily edited, and that is easily copied for someone else to run. To achieve these things, you’ll need to store your application in a file.
Let’s take a stab at doing just that.
A Traditional Program
Already the ancient Romans started the study of each new programming language or technology by using it to create a so-called “Hello, World” program. Such a program simply displays a message and does nothing else.
Let’s create and store a program that contains a couple of Scala commands and that we can launch as may times as we like. These print commands will serve:
println("Ave, Munde!")
println("Well, ave at thee, too!")
Create a new IntelliJ module for this experiment:
- File → New → Module.
- In the dialog window that pops up, make sure that Scala is selected. Press Next.
- Write Ave as the module’s name. But don’t press Finish yet. Instead...
- ... open More Settings at the bottom of the dialog.
Remove the text "src" from the Create source root
text field. Leave the checkmark next to it, though.
- (This step isn’t otherwise crucial, but doing
this gives you a module whose structure matches
that of O1’s other modules so that our A+ Courses
plugin can submit it for auto-grading. If you skip
this step, you get an
src
subfolder within the module that contains all the Scala files.)
- (This step isn’t otherwise crucial, but doing
this gives you a module whose structure matches
that of O1’s other modules so that our A+ Courses
plugin can submit it for auto-grading. If you skip
this step, you get an
- Hit Finish. The Ave module shows up in IntelliJ’s Project view.
Create a new Scala code file:
- Right-click Ave module and select New → File.
- You’re prompted for a file name. Enter
Ave.scala
- Hit Finish. The file shows up within the module and also opens up in IntelliJ’s editor. It is empty.
Write the program:
- Enter the two
println
commands in the empty file you just created. Compile the module (F10
). - Witness: Compilation fails. The Messages tab elaborates: Error: expected class or object definition. What’s wrong?
The underlying problem is that we haven’t set up our application as a proper object-oriented program. When we write a Scala application, we need to define a special “app object” that provides a starting point for program execution. This object can then activate (call) other program components as needed.
The GoodStuff module has an app object named GoodStuff
, which you’ve activated before
to run the application. The Pong module contains an app object named PongApp
. Our Ave
application, however, lacks such an object.
Writing an App Object
Here’s a template for an app object:
object MyOwnApplication extends App {
// This is an app object.
// The commands you enter here will be executed when the app runs.
}
App
data type.
The object now represents our application as a whole and enables
us to run the program.At this stage of O1, feel free to think of extends App
as simply a phrase that marks
an app object. In later chapters (e.g., 7.2) it will turn out that the extends
keyword
has many other uses as well.
A Tiny But Complete Scala Program
A larger program may consist of dozens, hundreds, or even more classes and singleton objects. However, for our tiny greeting program, we need just a single app object where we place the print commands.
Edit Ave.scala
to contain the following:
A tip for indenting
A handy way to indent code in IntelliJ is to select the lines
you wish to indent and press the Tab
key. Unindenting
works the same way with Shift+Tab
.
object Ave extends App {
println("Ave, Munde!")
println("Well, ave at thee, too!")
}
Now you can run the program by opening the menu for the Ave
file in the
Project tab and selecting Run 'Ave'. A still
easier way is to click the Play icon that appeared in the margin next to
the work object
in the code. Try it.
(This is also how you started GoodStuff and Pong back in Chapter 1.2. These and some alternative ways to launch a Scala app in IntelliJ were presented there.)
Notice that the output appears in IntelliJ’s Run tab at the bottom. An output area like this is called a text console (tekstikonsoli) or simply a console.
You have now written a complete Scala application.
A+ presents the exercise submission form here.
Reading Keyboard Input
The Ave app produces the same output each time it’s run, and the user has no way to affect what the program does as it runs. In constrast, most meaningful applications take in some sort of input (syöte) from their users, either directly or indirectly. Here are some examples:
- The program has a graphical user interface. The user can click on it to indicate what they wish the program to do.
- The program operates on data that it loads from files stored on the computer’s hard drive.
- The program interacts with the user in the text console. It pauses to wait for the user to enter lines of text as input.
We’ll get started with graphical user interfaces later in this chapter. Working with files will be discussed in Chapter 11.3. But first, let’s explore the third form of user interaction.
A text-based app in the console
Let’s write a program that works in IntelliJ’s Run tab as shown below.
Halt! Who is it? Pechkin the Postmaster Ave, Pechkin the Postmaster!
Enter
.The readLine
function
The library function readLine
receives, or “reads”, a single line of user input.
Calling readLine
suspends the program until the input has been received. The function
returns the input as a String
.
The interactive program described above can be implemented with readLine
:
import scala.io.StdIn._
object GreetingApp extends App {
println("Halt! Who is it?")
val name = readLine()
println("Ave, " + name + "!")
}
readLine
is to import
it first.
StdIn
is short for “standard input”, which here essentially
means input that the user enters through a text console.Type in (or copy–paste) the above program in IntelliJ. You can either edit the Ave
object or create a new file for this second app.
Run the program. See what it prints in the console and answer the program’s request for input. (N.B. You will need to click the console before you can use the keyboard to enter input.)
It’s also good to know that you can pass a string parameter to readLine
. If you do,
the function first prints the string as a prompt and then reads the user’s input off the
same line. Here’s an example:
val name = readLine("Halt! Who is it? ")
println("Ave, " + name + "!")
This produces interactions like the one below.
Halt! Who is it? Pechkin the Postmaster Ave, Pechkin the Postmaster!
Mini-assignment
Write a program that asks the user for two strings and surrounds the first string with the second as shown in these example runs:
Please enter a string: llama And a surrounding string: !? !?llama!?
Please enter a string: cad And a surrounding string: abra abracadabra
Write your code in an app object named Surround
. Define the app object
in a file named Surround.scala
. Create the file in the Ave module
next to Ave.scala
.
A+ presents the exercise submission form here.
Assignment: Odds (Part 5 of 9)
Let’s write a small test program for the Odds module from Chapters 2.4 and 2.5.
Our program will use keyboard input to create Odds
objects, call the objects’
methods, and print a report of the return values.
Task description
Two of the files in module Odds are relevant to this assignment. Odds.scala
you already
know; it defines class Odds
. Now take a look at OddsTest1.scala
. It defines an app
object, but the definition is incomplete and the app doesn’t actually use class Odds
at
all.
Flesh out the app object so that it produces an output that exactly matches the following example. (Of course, the user might well enter numbers other than the ones shown.)
Please enter the odds of an event as two integers on separate lines. For instance, to enter the odds 5/1 (one in six chance of happening), write 5 and 1 on separate lines. 7 2 The odds you entered are: In fractional format: 7/2 In decimal format: 4.5 Event probability: 0.2222222222222222 Reverse odds: 2/7 Odds of happening twice: 77/4 Please enter the size of a bet: 50.0 If successful, the bettor would claim 225.0 Please enter the odds of a second event as two integers on separate lines. 10 1 The odds of both events happening are: 97/2 The odds of one or both happening are: 70/29
Instructions and hints
- You can start by running
OddsTest1
as given. It reads in some input but doesn’t produce the correct output. - In
OddsTest1
, add the commands to createOdds
objects and call their methods.- Do not edit class
Odds
or copy any of it intoOddsTest1.scala
. Use the class as it is. - It’s important that you sequence the commands
right. Pay attention to where within
OddsTest1
you create newOdds
objects. You can create an instance only after you’ve read the required inputs; on the other hand, you need to create it before you can call any methods on it.
- Do not edit class
- Since
OddsTest1
andOdds
are in the same package, you can instantiateOdds
inOddsTest1
withoutimport
ing anything. - You’ll notice that the given code calls functions named
readInt
andreadDouble
. These two work likereadLine
, above, differing from it only in that they interpret user inputs as numbers. For example,readInt
returns a value of typeInt
, not aString
. - Hint: you can use
both
to compute the odds of an event occurring twice. (E.g., to roll a six twice is to roll a six and to roll another six.)
A+ presents the exercise submission form here.
Optional assignment: eliminate redundant code with abstraction
OddsTest1
features two pieces of code that do essentially the same thing: they
read in two numbers and use them as constructor parameters for a new Odds
object.
Avoid this unnecessary repetition with a different implementation:
- In
OddsTest1
, add a method calledrequestOdds
that takes no parameters. This effectful method reads in two integers, uses them to create anOdds
instance, and returns a reference to the new object. - Call
requestOdds
(twice).
A+ presents the exercise submission form here.
An Application with a GUI
Recap: An application program operates on some problem domain. The programmer creates a model of that domain. A user interface presents the model to the end user in some form, usually as images and/or text. Many user interfaces also let the user interact with the model, affecting the model’s state. Many applications have a graphical user interface (GUI) that consists of various visual elements and is typically displayed in a separate window.
A toy example of a model
The domain of the FlappyBug game is the two-dimensional game world; in the previous
chapter, we wrote the classes Bug
, Game
, and Obstacle
, which together model this
domain. Before we write a GUI for that model, let’s consider a simpler model and a GUI
that displays it.
Our example model consists of just a single class, Block
:
class Block(val size: Int, val location: Pos, val color: Color) {
override def toString = this.color.toString + " block at " + this.location
}
Below is a usage example. It works if you have the above class loaded in the REPL; the class is provided in the IntroApps module.
val model = new Block(20, new Pos(300, 50), Gray)model: Block = Gray block at (300.0,50.0)
Now let’s write a GUI that displays a view of a single Block
object set against a
solid background.
Quick recap of custom methods
Remember the Person
class from the end of Chapter 2.4? We created several instances of
it, including a Superman person that was created with this command:
val superman = new Person("Clark") { def fly = "WOOSH!" }
That object is an instance of the person class but also has a fly
method. In just a
moment, we’ll find a more concrete use for defining a method on a single instance.
Displaying a GUI window: o1.View
Fortunately, programmers don’t have to build a GUI for every application from scratch, pixel by pixel. Instead, they find a software library suitable for their purposes.
There are many GUI libraries. One well-known one is called Swing; we’ll use Swing in Chapter 12.3 to work with buttons, text fields, and the like. Right now, we’ll instead use O1’s own GUI library, which is particularly useful for building small apps whose GUI consists of geometric shapes. (This library is also compatible with Swing.)
Package o1
provides a class called View
. As its name suggests, this class can be used
to display a view to an object that models the app’s domain. Let’s use the following
Block
object as our model:
val model = new Block(20, new Pos(300, 50), Gray)model: Block = Gray block at (300.0,50.0)
Now to create the View
object. This object represents a single GUI window that displays
a single object of type Block
.
val viewOfBlock = new View(model) { def makePic = { val background = rectangle(500, 500, Black) val blockPic = rectangle(model.size, model.size, model.color) background.place(blockPic, model.location) } }viewOfBlock: o1.gui.mutable.ViewFrame[Block] = view of Block
View
. As a constructor
parameter, we pass in a reference to what the view will display.View
object
is, our particular View
instance has an effect-free method
makePic
that forms an image of the model. The image is of type
Pic
, and we form it using the Pic
tools familiar from earlier
chapters.Nothing graphical actually showed up when we entered that command in the REPL. This is
because we didn’t yet start up our GUI. Every View
object has an effectful method
that starts it. The following command displays our primitive GUI. Try it.
viewOfBlock.start()
Any View
object is capable of drawing itself onscreen and showing the image produced by
its makePic
method. So what we get is a window that contains the image of a block set
against a black background. The window also has the customary controls for minimizing and
closing it; that little bit of interactivity is automatically provided by View
without
us having to do anything about it.
An App
with a View
Let’s combine what we’ve covered in this chapter to create an app object that fires up a GUI view.
object BlockApp extends App {
val background = rectangle(500, 500, Black)
val block = new Block(20, new Pos(300, 50), Gray)
val viewOfBlock = new View(block, "An uninteractive test app") {
def makePic = {
val blockPic = rectangle(block.size, block.size, block.color)
background.place(blockPic, block.location)
}
}
viewOfBlock.start()
}
View
we construct.start
to make the GUI
visible onscreen. After that, all the code within our app object
has been executed but our application will keep running in its
separate window until the user signals otherwise.You can find this mini-app in the IntroApps module. It is ready to run.
That sure was a boring program. Thankfully, FlappyBug will be more interesting.
Side note: makePic
as an abstract method
Question: what happens if I remove makePic
from the above app?
Answer: you’ll receive a compile-time error message informing
you that you can’t create a View
object that doesn’t have a
makePic
method.
Explanation: the View
class has been defined so that even though
it doesn’t actually implement a makePic
method, it requires
such an implementation to exist on all objects of type View
.
In more technical terms, makePic
is an abstract method in
class View
. More on abstract methods in Chapter 7.2.
An optional practice task
If the previous example seems unclear or the next official assignment feels too difficult, you can practice on this small additional assignment.
Let’s construct a View
that displays the Earth and the Moon in space.
As our model, we’ll use an instance of class AreaOfSpace
and the two
instances of class CelestialBody
that are linked to it. Here is the
implementation of those classes (repeated from Chapter 2.6’s optional
section where the classes were introduced):
class CelestialBody(val name: String, val radius: Double, var location: Pos) {
def diameter = this.radius * 2
override def toString = this.name
}
class AreaInSpace(size: Int) {
val width = size * 2
val height = size
val earth = new CelestialBody("The Earth", 15.9, new Pos(10, this.height / 2))
val moon = new CelestialBody("The Moon", 4.3, new Pos(971, this.height / 2))
override def toString = s"${this.width}-by-${this.height} area in space"
}
That code is also available in Space.scala
in module IntroApps
. The related
file SpaceProgram.scala
contains starter code for a program that displays a
this sort of simple model of space in a View
:
object SpaceProgram extends App {
val space = new AreaInSpace(500)
val emptySpacePic = rectangle(space.width, space.height, Black)
val earthPic = circle(space.earth.radius * 2, MediumBlue)
val moonPic = circle(space.moon.radius * 2, Beige)
// Replace the question marks below with code that works.
val gui = new View(???, "A Very Simple View of Space") {
def makePic = ???
}
??? // Should launch the view that variable "gui" refers to.
}
AreaInSpace
.
It will be our domain model.Pic
s that we’ll put
together to generate a Pic
of the entire model.View
. Let’s call this variable gui
,
for example.Your task is to fill in the missing pieces:
View
’s first constructor parameter,
which specifies the model that the View
instance will depict.makePic
that places
the images of the Earth and the Moon in their
correct positions against emptySpacePic
. (In
practice, the Earth will be visible at the left
edge of the view, and the Moon near the right
edge.)View
(displaying
it onscreen).Make the changes in module IntroApps and try running the program.
See below for the solution. You can also submit your answer for feedback.
How to replace the first ???
(the constructor parameter)
Show the solutionHide the solution
AreaInSpace
that we
created earlier. We have a variable space
that refers to
that object, so you can replace the first question marks with
that variable name.A hint for replacing the second ???
(makePic
)
We need to place two pictures onto emptySpacePic
. Calling
the place
method a couple of times will do the trick.
You can use the space
variable to access the celestial bodies
and their correct positions (cf. Chapter 2.6).
Remember Chapter 2.3’s rotating-horse example? When you combine
method calls on Pic
s, keep in mind that Pic
objects are
immutable and the second place
operation should target the
output of the first.
How to replace the second ???
(makePic
)
Show the solutionHide the solution
Here are a couple of different ways to phrase a solution:
def makePic = emptySpacePic.place(earthPic, space.earth.location).place(moonPic, space.moon.location)
def makePic = {
val earthAdded = emptySpacePic.place(earthPic, space.earth.location)
earthAdded.place(moonPic, space.moon.location)
}
How to replace the last ???
(launching the view)
Show the solutionHide the solution
gui
that refers to the view, and
the relevant method is named start
, so gui.start()
works.A+ presents the exercise submission form here.
Assignment: FlappyBug (Part 3 of 17: The Beginnings of a GUI)
Introduction
Here’s some starter code for an app object. You can also find this code in FlappyBugApp.scala
.
import constants._
object FlappyBugApp extends App {
val sky = rectangle(ViewWidth, ViewHeight, LightBlue)
val ground = rectangle(ViewWidth, GroundDepth, SandyBrown)
val trunk = rectangle(30, 250, SaddleBrown)
val foliage = circle(200, ForestGreen)
val tree = trunk.onto(foliage, TopCenter, Center)
val rootedTree = tree.onto(ground, BottomCenter, new Pos(ViewWidth / 2, 30))
val scenery = sky.place(rootedTree, BottomLeft, BottomLeft)
val bugPic = Pic("ladybug.png")
def rockPic(obstacle: Obstacle) = circle(obstacle.radius * 2, Black)
// INSERT YOUR OWN CODE BELOW.
}
scenery
stores the end result. It isn’t necessary that you understand
precisely how the background was constructed, but you can find an
explanation in the optional material at the end of Chapter 2.5bugPic
stores an image that we’ll use to depict
the bug in the GUI. The function rockPic
forms a Pic
of a
given obstacle. You’ll need these components in the next part of
the FlappyBug assignment but not just yet. For now, focus on
displaying the background scenery in a View
.Recommended workflow and hints
Reminder: please don’t forget to ask for a hint on our forums or at the labs if you’re
stuck. Also, if you have trouble with this assignment, you might want to practice on the
optional SpaceProgram
assignment above.
- Create a new object that will serve as the application’s domain
model. A
Game
object is a suitable model for our FlappyBug app.- A simple
new Game
will do to create the object (Chapter 2.6). You don’t need to pass in any constructor parameters . - Also create a variable that refers to the game object. Name it as you please.
- A simple
- Create a
View
that depicts theGame
in a GUI window.- Use "FlappyBug" as the title.
- The basic idea is similar to the block app,
but now the domain model isnt a
Block
but aGame
object. When you create theView
, pass in two constructor parameters: a reference to yourGame
object and the window title as a string. - Define a variable that refers to your
View
object (likeviewOfBlock
earlier). Normally, you could name such a variable freely, but please use the namegui
here to ensure that automatic assessment works properly for this assignment.
- Write a
makePic
method on the view. For now, just have it return the background picture (scenery
). You’ll add the bug and the obstacle in just a bit. - Add a
start
command to start the GUI.
Now when your run the program, you should see a simple scenery in a window titled
"FlappyBug". The result isn’t much different from what we’ve already been able to produce
with the show
function. Yet.
A+ presents the exercise submission form here.
Assignment: FlappyBug (Part 4 of 17: Fleshing Out the View)
Improve the makePic
method. It should construct and return an image of the game’s current
state by combining the scenery, the bug’s image, and an image of an obstacle so that the
bug and the obstacle have been place
d against the scenery in their correct positions.
A few hints:
- Use the images given as
scenery
andbugPic
. - At least for now, let’s depict obstacles as “rocks” that are
simply solid black circles. Calling
rockPic
on an obstacle with a radius of 5 gives you a pebble; a radius of 150 yields an almighty chunk of rock. - Given what you did in Chapter 2.6, the
Game
object should have two variables:obstacle
andbug
. You can use them to access the game’s bug and the obstacle. You’ll need to do so.- E.g.,
myGameObject.bug
- E.g.,
- You can access the positions of the game’s bug and obstacle via
their
pos
attributes (Chapter 2.6).- E.g.,
myGameObject.bug.pos
- E.g.,
- Place the bug and the obstacle at their initial locations as indicated
by their
pos
es.- Use something in the vein of
scenery.place(referenceToObstacle, positionOfObstacle)
. - Cf.
BlockApp
above (and the optionalSpaceProgram
). - You may want to think back to Chapter 2.3’s
horse-rotating example to remember how to
apply a sequence of method calls on a
Pic
.
- Use something in the vein of
Run the program. You should see both the bug and the obstacle at their initial positions. They don’t move. Yet.
A+ presents the exercise submission form here.
Recap and clarifications: the View
class, start
, and makePic
There’s nothing really new in this box. If you feel like you
understood the above, you can skip this elaboration on what
a View
is and how it behaves.
The two main components of an application are its internal model and a user interface. The user interface makes the model visible and typically enables the human user to somehow interact with the model (Chapter 1.2).
View
is a class whose instances (View
objects) are graphical
windows that serve as user interfaces. Each such View
object is
associated with another object, which serves as the application’s
internal model and which the View
window displays as graphics.
When you create a View
object, you need to indicate which object
will be the internal model and therefore displayed in the view.
For instance, in the FlappyBug example above, we wrote new View(game, ...)
,
making this a View
that displays information about a game object.
Just creating a View
object does not display the user-interface
window. That happens only when you start the view by calling its
start
method. When you do, the window not only shows up but also
starts responding to user actions in the window (which we’ll discuss
in Week 3).
makePic
method
just “ran itself”. I defined the method but
never called it anywhere in my program.Once you’ve start
ed a View
, the View
draws itself onscreen
using its own makePic
method, which you’ve defined on it. It’s
true that you don’t have to expressly invoke makePic
yourself,
since the View
object has been programmed to take care of that on
its own after it’s been started. The View
window displays exactly
the picture that makePic
returns.
View
and makePic
will soon become more familiar as Week 3
continues right where Week 2 left off.
Optional activity: write prettier code
In the given FlappyBugApp
, the background image is
constructed with a sequence of commands that use multiple
temporary variables (e.g., foliage
, ground
), each of
which stores a partial image but has no purpose once the
final scenery has been constructed. We can make our code
a bit more elegant by structuring it differently. Try the
following.
Can you restructure that part of the code so that
scenery
isn’t a variable but a parameterless function that returns the scenic image? Like this:def scenery = { // place the code that constructs the image here }
In this solution, temporaries such as
foliage
become local variables as you define them withinscenery
’s body.How about changing
def scenery
toval scenery
in the modified solution? Does that work? Can you tell what difference this makes, if any?
Summary of Key Points
- A Scala application is launched through an app object. You can write
an app object by including
extends App
in the definition of a singleton object.- You may not need to write any methods on an app object. The commands in the object’s body are executed one by one when the application is launched.
- In a larger application, the app object activates other program components.
- The Scala library provides functions for reading keyboard input from the user through the text console.
- A typical application’s program code features a domain model and a user interface that depicts and operates on the model.
- There are various software libraries that help programmers build
graphical user interfaces.
- One GUI library is provided as part of
package
o1
. A key component of this library is theView
class, whose instances represent GUI windows.
- One GUI library is provided as part of
package
- Links to the glossary: app object; input, I/O; model, user interface, graphical user interface (GUI); text console.
Feedback
Please note that this section must be completed individually. Even if you worked on this chapter with a pair, each of you should submit the form separately.
Credits
Thousands of students have given feedback that has contributed to this ebook’s design. Thank you!
The ebook’s chapters, programming assignments, and weekly bulletins have been written in Finnish and translated into English by Juha Sorva.
The appendices (glossary, Scala reference, FAQ, etc.) are by Juha Sorva unless otherwise specified on the page.
The automatic assessment of the assignments has been developed by: (in alphabetical order) Riku Autio, Nikolas Drosdek, Joonatan Honkamaa, Jaakko Kantojärvi, Niklas Kröger, Teemu Lehtinen, Strasdosky Otewa, 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 did the technical implementation, relying on Teemu’s Jsvee and Kelmu toolkits.
The other diagrams and interactive presentations in the ebook are by Juha Sorva.
The O1Library software has been developed by Aleksi Lukkarinen and Juha Sorva. Several of its key components are built upon Aleksi’s SMCL library.
The pedagogy of using O1Library for simple graphical programming (such as Pic
) is
inspired by the textbooks How to Design Programs by Flatt, Felleisen, Findler, and
Krishnamurthi and Picturing Programs by Stephen Bloch.
The course platform A+ was originally created at Aalto’s LeTech research group as a student project. The open-source project is now shepherded by the Computer Science department’s edu-tech team and hosted by the department’s IT services. Markku Riekkinen is the current lead developer; dozens of Aalto students and others have also contributed.
The A+ Courses plugin, which supports A+ and O1 in IntelliJ IDEA, is another open-source project. It was created by Nikolai Denissov, Olli Kiljunen, and Nikolas Drosdek with input from Juha Sorva, Otto Seppälä, Arto Hellas, and others.
For O1’s current teaching staff, please see Chapter 1.1.
Additional credits appear at the ends of some chapters.
extends
keyword as “is a kind of”.