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.

Chapter 7.5: Superclasses and Subclasses

Questions Answered: Say I have a regular class; how can I define a subtype for it? How do the classes and traits of the Scala API form a type hierarchy? I heard someone talk about “abstract classes”; what are those?

Topics: Class-based inheritance: subclasses that inherit from a superclass. Some type hierarchies in the Scala API. Abstract classes.

What Will I Do? There’s some reading, a good chunk of which is optional but potentially interesting. There’s one small programming assignment.

Rough Estimate of Workload:? An hour or so.

Points Available: B20.

Related Modules: Traits.

Introduction

In the preceding chapters, we used traits to define supertypes for multiple classes. This chapter complements the preceding ones: we’ll see how a regular class may also serve as a supertype, with other classes inheriting from it.

Let’s Continue with Shapes

In the previous chapter, we defined the trait `Shape` and an inheriting `Rectangle` class:

```trait Shape:
def isBiggerThan(another: Shape) = this.area > another.area
def area: Double
```
```class Rectangle(val sideLength: Double, val anotherSideLength: Double) extends Shape:
def area = this.sideLength * this.anotherSideLength
```

Suppose we also want to represent squares — that is, rectangles with four sides of equal length? We’d like to be able to write `Square(10)` and the like.

Of course, we might simply write a `Square` class that inherits `Shape`:

```class Square(val sideLength: Double) extends Shape:
def area = this.sideLength * this.sideLength
```

The bothersome thing about this solution is that the code is quite redundant: the algorithm for computing the area of a square is the same as that for a rectangle; it just happens that the sides are equal in length. The code isn’t up to par in terms of conceptual modeling, either: it makes squares a subtype of `Shape` alongside rectangles, whereas we humans prefer to think of a squares as a special case of a rectangle; each square is a square, a shape, and a rectangle.

The fix is simple: we can define squares as a subtype of rectangles, as shown in the diagram below. We can do this even though `Rectangle` is a regular class, not a trait.

Subclasses and Superclasses

Let’s add something to class `Rectangle`:

```open class Rectangle(val sideLength: Double, val anotherSideLength: Double) extends Shape:
def area = this.sideLength * this.anotherSideLength
```

This is a regular `class`, which can be instantiated directly, but it is open (avoin) for extension. By adding the keyword `open`, we indicate that this class is designed to be freely usable as a superclass (yliluokka): other classes may inherit from it.

`Square` can then be defined as `Rectangle`’s subclass (aliluokka):

```class Square(size: Double) extends Rectangle(size, size)
```

We use the familiar `extends` keyword, but this time we follow it with the name of a regular class rather than a trait. The subclass `Square` inherits its superclass, and so all `Square` objects now have the additional type of `Rectangle`.

`Square` has only one constructor parameter that determines the length of each side.

To create an instance of a subclass, any initialization steps that the superclass demands must also be performed. A subclass may pass constructor parameters to its superclass; the idea is the same as with the traits of Chapter 7.3. In this example, we state that whenever a `Square` object is created, we initialize a `Rectangle` so that each of its two constructor parameters (each side length) gets the value of the new `Square`’s single constructor parameter.

How mandatory is the `open` keyword?

There are reasons why it’s not a good idea to write subclasses for any random class that isn’t designed to be inherited from. Those reasons tend to come to the fore in larger-scale programming projects and won’t be obvious from O1’s introductory-level materials. However, the optional material at the end of this chapter hints at some of the complications in class-based inheritance.

Anyhow, we explicitly write `open` to state that a Scala class has been designed for inheritance and programmers are free to inherit from it as they please. If you omit `open`, any subtypes that your class might have should be defined in the same file. Technically, omitting `open` does not utterly prevent inheriting from the class in other files, but the Scala compiler will issue warnings about the suspicious code, and it’s best to avoid such inheritance. (Cf. sealing a class with `sealed`, which completely prevents direct subtypes from being defined in other files; Chapter 7.4.)

In some exceptional circumstances, it is reasonable to write a subclass for a non-open class that is defined elsewhere. In that case, the programmer may disable the compiler warning with ```import scala.language.adhocExtensions```. In O1, you should have no reason to do this.

Inheritance vs. traits

Inheriting from a superclass looks much like inheriting from a trait. The two techniques are indeed closely related.

There are some differences, though; let’s compare. First, consider traits and how the `Rectangle` class extends the `Shape` trait:

When using a `trait`

Example

The supertype is represented by a trait.

`trait Shape`

Each subtype inherits that trait.

`class Rectangle extends Shape`

A trait may define abstract methods and variables.

`def area: Double`

A trait cannot be instantiated directly.

One does not simply write `Shape()`.

A class (or trait) may directly inherit multiple traits.

`class X extends Trait1, Trait2, Trait3` is fine.

A trait cannot pass constructor parameters to its supertype(s).

`trait Trait1 extends Trait2(someParams)` is invalid.

And here is a similar table about inheritance and the example of `Rectangle` as a superclass for `Square`:

When inheriting from a regular `class`

Example

The supertype is represented by a regular class (which is best to mark as open, if meant for inheritance).

`open class Rectangle`

Each subtype inherits that superclass.

`class Square extends Rectangle`

An ordinary class cannot define abstract methods or variables. (But some classes can. See below.)

All the methods on `Rectangle` have a method body.

A superclass can be instantiated directly.

`Rectangle(...)` works.

(In Scala and many other languages:) A class cannot have more than one immediate superclass.

`class X extends Super1, Super2` is invalid.
(But `class X extends Super1, Trait1, Trait2` is fine.)

Any `class` may pass constructor parameters to its supertype(s).

`class Square(size: Int) extends Rectangle(size, size)` is fine.

There are many programs where it’s reasonable to use either of the above.

Assignment: Items within Items

Introduction

Imagine we’re working on an application that needs to represent items of various sorts. We have a simple class `Item`:

```class Item(val name: String):
override def toString = this.name
```

For this small programming assigment, let’s adopt the following goal: we wish our program to have not only “simple items”, as defined above, but also items that can contain other items. For instance, we might have a bag that contains a book and a box, and the box might further contain a ring.

Write a subclass for `Item`. Name it `Container`. This subclass will represent items that can contain other items, such as bags and boxes:

• Containers each have a name, just like other items do.

• They have an `addContent` method, which places an item within the container.

• And a `contents` method that returns the previously added items in a `Vector`.

• Their `toString` implementation differs from that of other items.

Your class should work as shown below.

```val container1 = Container("box")container1: o1.items.Container = box containing 0 item(s)
container1res0: o1.items.Container = box containing 1 item(s)
val container2 = Container("bag")container2: o1.items.Container = bag containing 0 item(s)
container2res1: o1.items.Container = bag containing 2 item(s)
container1.contentsres2: Vector[o1.items.Item] = Vector(ring)
container2.contentsres3: Vector[o1.items.Item] = Vector(book, box containing 1 item(s))
```

The `toString` method’s return value should count only the container’s immediate contents. For instance, in the REPL session above, the bag is shown as containing only two items, even though the box in the bag further contains the ring.

(How could we count all the “contents of the contents”, too? You’ll see in Chapter 12.2.)

Instructions and hints

• In `o1.items` within the Traits module, you’ll find that `Item` class. It’s missing the `open` keyword, though; type that in.

• In the same package, you’ll find some starter code for `Container`.

• Don’t forget to pass a constructor parameter to the superclass `Item`.

• Don’t use `val` to (re)define the instance variable `name` within the `Container` subclass. That variable is already defined in the superclass. It’s perfectly fine to give `Container`’s constructor parameter the name `name`, though.

• Note that what you `override` in this assignment isn’t the generic `toString` from `AnyRef`, as in many other programs, but the `toString` implementation in `Item`.

• Can you implement the `toString` in `Container` so that you use the superclass’s implementation rather than directly accessing the container’s name? (This is optional.)

• Do not add any public members in the class beyond what was requested. Private members you are free to add as you see fit.

A+ presents the exercise submission form here.

A Few Words about Abstract Classes

In addition to regular classes and traits, one may define abstract classes ( abstrakti luokka). Abstract classes resemble traits in several ways but aren’t quite the same thing.

For our purposes in O1, abstract classes aren’t a central topic; we’ll generally prefer traits for our subtyping needs. As your programming experience grows, you’ll learn to choose between traits and abstract classes. For now, it is enough to be aware that abstract classes exist; that much is good to know because they aren’t a rarity in Scala programs or in programs written in other languages. Not all programming languages have traits and abstract classes as separate concepts.

Let’s see a quick example. In a Chapter 7.3 program, we had this trait named `Entity`:

```trait Entity(val name: String):
def contact: NaturalPerson
def kind: String
override def toString = s"\$name (\$kind)"
```

Two of the methods are abstract. Such methods, whose implementation is left to subtypes to take care of, cannot appear in completely regular classes. However, the following alternative definition of `Entity` is valid.

```abstract class Entity(val name: String):
def contact: NaturalPerson
def kind: String
override def toString = s"\$name (\$kind)"
```

The word `abstract` turns this into an abstract class. Such a class may contain abstract methods just like a trait can. And just like a trait cannot be directly instantiated, neither can an abstract class. Abstract classes are open for extension by default, so there is no need to write `open`.

A class that is not abstract may be referred to as a concrete class.

An abstract class is similar to a trait in some ways and similar to a concrete superclass in other ways. Let’s compare:

Trait

Abstract
superclass
Concrete
superclass

Can it have abstract methods?

Yes.

Yes.

No.

Can it be directly instantiated?

No.

No.

Yes.

Can it pass constructor parameters to its supertype(s)?

No.

Yes.

Yes.

Can you inherit several of them (listed after `extends`)?

Yes.

No.

No.

Generally speaking, should I use a trait or an abstract class?

Rule of thumb: Unless you have a specific reason to use an abstract class, use a trait instead, since traits are more flexibly extendable.

It can be tricky to choose between a trait and an abstract superclass. However, in O1, such decisions are generally made for you and provided in the assignment specifications. You can worry about learning to make these decisions yourself later, in Programming Studio 2, for example. For some more information, you could also take a look Scala Cookbook or Programming in Scala, which are some of the recommendations on our Books and Other Resources page.

Class Hierarchies in the Scala API

Like traits, `class`-based inheritance is useful in forming type hierarchies.

Some examples of hierarchies can be found in Scala’s standard API. Let’sconsider a few.

A hierarchy of GUI elements

The package `scala.swing` provides a selection of classes that represent GUI elements, building blocks for graphical user interfaces. The diagram below depicts a part of this hierarchy.

Chapter 12.4 contains an introduction to the GUI library known as Swing. That optional chapter is at the rear end of O1 and this ebook, but if you’re itching to read more about GUIs, go ahead and read it. Now that you’ve been introduced to inheritance, you should have the sufficient prerequisite knowledge for the chapter.

The `Option` hierarchy (and sealed superclasses)

There’s a small class hierarchy associated with the `Option` type, too.

Since Chapter 4.3, you’ve known that there are two kinds of `Option` objects. Any object of type `Option` is either a `Some` object that contains a value or `None`. This is actually an example of inheritance: `Option` is an abstract class that the concrete class `Some` and the singleton object `None` extend.

Chapter 7.4 mentioned how to seal a trait: the `sealed` keyword makes it impossible to directly extend a trait except within the file that defines the trait itself. A superclass can also be sealed, and `Option` is just such a sealed class.

As we noted in Chapter 4.3, an `Option` can be either a `Some` or `None` (which are defined in the same file) but it can never, ever be anything else. Which is exactly what you want when you use `Option`. You can’t extend `Option` with a class of your own, and that’s good.

The mother of all classes: `Any`

Let’s examine some objects in the Scala REPL:

```val miscellany = Vector(123, "llama", true, Vector(123, 456), Square(10), IArray(1, 2, 3))miscellany: Vector[Any] = Vector(123, llama, true, Vector(123, 456), o1.shapes.Square@114c3c7, Array(1, 2, 3))
```

We create a vector that contains some completely disparate objects: an `Int`, a `String`, a `Boolean`, a `Vector` of `Int`, a `Square`, and an immutable array (a sort of collection).

Scala infers that the type of the vector’s elements is `Any`. That is, what we have is a “vector of any sorts of objects”. This suggests that integers, vectors, squares, and what have you, are all of type `Any`.

All Scala classes and singleton objects — including those you write — automatically inherit from a class called `Any`, even though we don’t usually record this inheritance explicitly in code. All the objects in a Scala program always have the `Any` type in addition to any other types they may have.

It’s possible to use this top-level class as a type for a variable, as illustrated below.

```var someObject: Any = "kumquat"someObject: Any = kumquat
someObject.isInstanceOf[Any]res4: Boolean = true
someObject.isInstanceOf[String]res5: Boolean = true
someObject.isInstanceOf[Square]res6: Boolean = false
someObject = Square(10)someObject: Any = o1.shapes.Square@ecfb83
someObject.isInstanceOf[Any]res7: Boolean = true
someObject.isInstanceOf[String]res8: Boolean = false
someObject.area-- Error: ... value area is not a member of Any
```

As the name suggests, you can use a variable of type `Any` to refer to any object. The object can be a string or a square, for instance.

So, the static type of `someObject` is `Any`, and the expression `someObject.isInstanceOf` is valid because (and only because) the `isInstanceOf` method is defined in the `Any` class and is therefore available on any Scala object.

The attempted method call `someObject.area` fails even though the variable happens to store a `Square` object which has an `area` method. The variable’s static type limits what you can do with it.

In most cases, it’s not sensible to use variables of type `Any`, since the type’s genericity so constricts what you can do with such variables. With `Any` as the static type, you can use the variable only for the operations that are defined on `Any`. Those extremely generic methods that are common to all Scala objects include `isInstanceOf`, `toString`, `==`, `!=`, and a handful of others. Generally, it makes sense to use variables with more specific types, which is of course what we’ve been doing already. (See the optional material below for a further discussion.)

The mother of most classes: `AnyRef` a.k.a. `Object`

Scala’s root type `Any` divides in two main “branches”. It has two immediate subclasses, `AnyVal` and `AnyRef`:

This division to `AnyRef` and `AnyVal` has to do with the way the Scala language is implemented and isn’t too significant to the Scala beginner or for learning the basics of programming more generally. Nevertheless, it’s good to be aware that these types exist so you know why they sometimes crop up in Scaladocs, REPL outputs, and error messages.

`AnyVal` is a superclass for some API classes that define certain data types that are simple but operate more efficiently than other classes do. The familiar data types `Int`, `Double`, `Boolean`, `Char`, and `Unit` descend from `AnyVal`, as do a few others. It’s relatively uncommon to extend `AnyVal` in an application; in O1, we don’t do that at all.

`AnyRef`, on the other hand, is a superclass for all other classes and singleton objects. The classes `String` and `Vector`, for instance, derive from `AnyRef`, as does the `Item` class we just wrote.

When using the common JVM-based implementation of Scala (as we do; Chapter 5.4), `AnyRef` is sometimes (and somewhat confusingly) also known by the name `Object` for JVM-specific technical reasons.

We can spot `AnyVal` and `AnyRef` a.k.a. `Object` in the REPL, too:

```val miscellany2 = Vector(123, true)miscellany2: Vector[AnyVal] = Vector(123, true)
val miscellany3 = Vector("llama", Vector(123, 456), Square(10))miscellany3: Vector[Object] = Vector(llama, Vector(123, 456), o1.shapes.Square@667113)
```

`Int` and `Boolean` descend from `AnyVal`.

`String`, `Vector`, and `Square` descend from `Object`, which is effectively synonymous with `AnyRef`.

One more: `Matchable`

In addition to the aforementioned very generic supertypes at the top of Scala’s hierarchy, you may run into one more: the `Matchable` trait is a supertype for all Scala types on which pattern matching (`match`) works. Both `AnyRef` and `AnyVal` inherit `Matchable`, so `Matchable` is nearly as all-encompassing as `Any`. (Pattern matching works on almost all types in Scala, but there are some very exceptional types that don’t have the `Matchable` trait. For more information, you could see online, but for course purposes, there’s no need to.)

A bit more on `AnyRef` and `AnyVal`

Some readers (who already know something about the JVM/Java) may wish to know that in the JVM-based Scala implementation, subclasses of `AnyVal` have been implemented as JVM primitives such as `int` and `double`, whereas classes that derive from `AnyRef` are implemented as classes within the JVM.

The names `AnyRef` and `AnyVal` reflect this implementation. The former’s implementation relies of object references, the latter’s implementation on primitive values. `AnyVal`s must be immutable and conform to other strict conditions as well. When used in the right places, `AnyVal`s can improve efficiency.

Tailoring Instances of a Supertype

In Chapter 2.4, you learned to create an object that has an instance-specific method in addition to the methods defined in a class:

```object superman extends Person("Clark"):
def lenna = "WOOSH!"
end superman// defined object superman
```

Since then, we’ve used this technique in combination with `View`s: we have defined singleton objects that extend `View` and have custom methods.

Tailoring instances in this way is actually a form of inheritance. For example, what the above command actually does is inherit a single object from the `Person` superclass. Along the same lines, we have written diverse implementations for the abstract `makePic` method of the supertype `View`.

When creating a single object, you can combine superclasses and traits flexibly in various other ways as well. Read on if you wish.

Defining a subtype “on the fly”

You can also inherit a trait “on the fly” as you create an object.

To set up the next example, let’s define a couple of traits and one concrete class. These three types are entirely distinct from each other.

```class Animal(val species: String):
override def toString = "an animal, more specifically a " + this.species
trait Spitting:
def spit = "ptui!"
trait Humped:
def numberOfHumps: Int// defined class Animal
// defined trait Spitting
// defined trait Humped
```

Let’s try a new way of creating an object:

```val pet = new Animal("llama") with Spittingpet: Animal & Spitting = an animal, more specifically a llama
```

We define, “on the fly”, a new subclass of `Animal` that has no specified name and that also inherits the `Spitting` trait. We immediately instantiate this new type to produce a single instance of it.

The word `new` is required in command such as this, which not only create a new instance but also define a new type for it. Note the use of `with` as well.

This object is of the combined type `Animal & Spitting` and has all the properties of `Animal`s as well as all the properties defined in the `Spitting` trait:

```pet.speciesres9: String = llama
pet.spitres10: String = ptui!
```

Of course, we could have also defined a named class, as shown below, and instantiated it as per usual.

```class Llama extends Animal("llama"), Spitting// defined class Llama
```

Adding methods on a type defined “on the fly”

Let’s continue our toy example. We’ll create an object of a type that:

• is a subclass of `Animal`;

• additionally inherits the traits `Humped` and `Spitting`; and

• implements the abstract method `numberOfHumps` in the `Humped` trait in a specific way.

```val shipOfTheDesert = new Animal("dromedary") with Humped with Spitting:
def numberOfHumps = 1shipOfTheDesert: Animal & Humped & Spitting = an animal, more specifically a dromedary
```

Finally, here’s how you could use the same technique to produce an object of type `Spitting` with its own particular implementation of `toString`:

```val fisherman = new Spitting:
val name = "Eemeli"
override def toString = this.namefisherman: Spitting = Eemeli
```

Here we followed `new` with the name of a trait rather than a concrete class. However, this command does not directly instantiate the trait (which isn’t even possible). Instead, it defines a new anonymous type that inherits the trait and additionally has the properties listed below. It is that new type that is then instantiated.

Terms for googling: scala trait mixin, scala anonymous subclass.

Choosing static types for variables

Rule of thumb: make the static types of your variables “wide” — this applies to parameter variables especially. That is, where possible, we’d like our parameters to have a superclass or a trait as their type rather than a more specific class. That way, our methods and classes will be more generally useful and easier to modify.

Compare:

```def doSomething(circle: Circle) =
// ...
```

vs.

```def doSomething(shape: Shape) =
// ...
```

The first definition is sensible in case `doSomething` should work only on circles (say, because it depends on being able to access the given object’s radius, which other shapes don’t have). Otherwise, the second definition is probably better, since it works on different shapes, including future subclasses of `Shape` that haven’t even been written yet.

You can’t always generalize; otherwise we’d just give everything the `Any` type. But do generalize when you can.

Between public and private: `protected`

A subclass’s instances also have the superclasses’ `private` variables as part of their state. Inherited methods commonly use those private variables. However, you can’t directly refer to a private member of a superclass from the subclass’s program code. The same goes for private members on traits.

However, Scala, like some other languages, features another access modifier, `protected`. This modifier allows precisely what we just said `private` disallows: a `protected` variable or method is accessible not only to the class or trait itself but also within the code of its subtypes. (But not just anywhere, like a public member is.) An internet search should bring up many examples.

Multiple inheritance

As noted above, a class can extend only a single superclass directly. Why?

Search online for multiple inheritance (moniperintä). You may also wish to look up the “deadly diamond of death” that is sometimes associated with multiple inheritance and that is held to be a serious problem by some but not all programmers.

And here is some slightly provocative but interesting reading (mostly to those students who already know something about Java and its interface construct):` 'Interface' Considered Harmful <http://blog.cleancoder.com/uncle-bob/2015/01/08/InterfaceConsideredHarmful.html>`_.

If my class inherits multiple traits, which method implementations do I get?

Here’s a simple example:

```trait X:
def method: String
trait A extends X:
override def method = "a’s method"
trait B extends X:
override def method = "b’s method"// defined trait X
// defined trait A
// defined trait B
class AB extends A, B
class BA extends B, A// defined class AB
// defined class BA
AB().methodres11: String = b’s method
BA().methodres12: String = a’s method
```

For more information, look up scala linearization or see Books and Other Resources page for further reading.

The Liskov substitution principle

“Square as a subclass of rectangle” is a classic example when discussing the Liskov substitution principle, which we’ll only paraphrase here. This well-known design guideline is often held up as a criterion of object-oriented program quality.

For a class S to follow this principle, the following must be true:

If S is a subclass of T, all operations that are available and meaningful on instances of T are equally available and meaningful on instances of S.

In other words: where you have an instance of T, you can also use an instance of S.

Let’s return to the shape example and these two classes that we defined earlier:

```class Rectangle(val sideLength: Double, val anotherSideLength: Double) extends Shape:
def area = this.sideLength * this.anotherSideLength
```
```class Square(size: Double) extends Rectangle(size, size)
```

Does this code follow the Liskov substitution principle? What if we used `var` instead of `val` in class `Rectangle`? Recall: our goal when writing `Square` was to model the fact that a square is a rectangle whose sides are equal in length.

More in Wikipedia:

On dependencies between classes/traits

The chapter on traits (7.3) already noted the asymmetric relationship between a subtype and a supertype: we define each subtype in terms of its supertype(s), not the other way around. This applies to inheritance, too:

• In a subclass definition, we record the superclass that the subclass extends. Given that relationship, we can rely on the inherited methods being available for us to use within the subclass. We can write things like `this.methodFromSuperclass`. We may also use the `super` keyword to refer to the superclass definition.

• We do not record the inheritance relationship in the superclass, and the superclass’s code is independent of the subclasses in this respect. We can't call `this.methodInSubclass`; we can invoke methods on `this` only if they are common to all instances of the supertype. There is no `sub` keyword.

If superclasses were dependent on their subclasses, changing those subclasses would necessitate changes in the superclass. That would be quite vexing. For instance: It’s fairly common to extend a superclass defined in a library (e.g., `View`). There is no way that the library’s creator can know all the possible subclasses that may be created for their class or react to changes in those subclasses.

On the other hand, it’s great that we can add methods to a superclass and those methods will then be available in all extending classes. Often, this works fine, but sometimes, we run into a weakness in inheritance-based program design:

On fragile superclasses

The fragile base class problem refers to situations where it’s impossible to modify a superclass without knowing details about its subclasses.

As one example, consider adding a method to a superclass: what if the new method happens to have the same name as one or more of the methods in the subclasses? We have a serious problem.

In a language such as Scala, our program will break down with a compile-time error that complains about a missing `override` modifier. In languages that don’t have such a modifier or that make it optional, we may get surprising and erroneous runtime behavior instead.

O1’s follow-on courses will discuss object-oriented design more deeply. In the meantime, you may find the Wikipedia article on fragile base classes interesting; see also composition over inheritance.

Preventing overriding and inheritance with `final`

If you add the `final` modifier in front of a `def`, the method can’t be overridden: instances of all subtypes will inherit the method as is. An attempt to override it will bring a compile-time error.

In front of `class`, the same `final` keyword disallows inheritance from that class altogether. (Cf. `sealed`, which limits direct inheritance to a single file.)

When used appropriately, the `final` modifier may make programs easier to comprehend and prevent inappropriate use of a class. Some programs’ efficiency is improved by `final`, since the compiler doesn’t need to worry about overriding.

Many of the classes in the standard Scala API are `final`.

Summary of Key Points

• You may extend not only traits but regular classes, too. Subclasses, which represent more specific concepts, then inherit the generic properties defined in the superclass.

• You may define a class as abstract, in which case it can contain abstract methods and variables just like a trait can. An abstract class can’t be instantiated directly but only via its subclasses.

• Traits and abstract superclasses have much in common, but there are differences, too. The exact differences depend on the programming language. (Some languages don’t have these as separate concepts.)

• In O1, we’ll be using traits. For purposes of the course, pretty much all you need to know about abstract classes is that they’re similar to traits.

• In Scala, all classes are part of a hierarchy whose base is the API class `Any`.

• Links to the glossary: inheritance, subclass, superclass, type hierarchy, `Any`; abstract class; static type, dynamic type; open class, sealed class; `final`.

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 and so 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, Kaisa Ek, Joonatan Honkamaa, Antti Immonen, Jaakko Kantojärvi, Niklas Kröger, Kalle Laitinen, Teemu Lehtinen, Mikael Lenander, Ilona Ma, 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 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 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.

Posting submission...