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.

Kieli vaihtuu A+:n sivujen yläreunan painikkeesta. Tai tästä: Vaihda suomeksi.

# Chapter 5.3: Objects as Functions, Classes as Objects

Questions Answered: Are classes objects? Are objects classes? Is a function an object or is an object a function? Or maybe an object is like a package? Can I keep my head together?

Topics: `apply` methods. Companion objects. Some skippable bonus topics.

What Will I Do? Read, mostly.

Rough Estimate of Workload:? Just half an hour, maybe?

Points Available: B5.

Related Modules: None.

## Introduction

In this relatively short chapter, we’ll continue to study just how ubiquitous objects are in Scala programs. We’ll encounter a handful of topics related to this theme.

## The Special Method `apply`

### Some example code to begin with

```val myVector = Vector("first", "second", "third", "fourth", "fifth")res0: Vector[String] = Vector(first, second, third, fourth, fifth)
myVector.apply(3)res1: String = fourth
myVector(3)res2: String = fourth
```

Consider the following questions.

1. You can obtain an individual element with `myVector(index)` or with the longer expression `myVector.apply(index)`. Why are there two different-looking but fundamentally similar ways of doing the same thing?

2. You learned to command objects via method calls, so `myVector.apply(index)` looks legitimate. But isn’t there something odd about the expression `myVector(index)`? It uses a reference to an object (from `myVector`) and somehow passes the value of `index` as a parameter to that object. The command has the appearance of a function call but seems more like an “object call”, if there is such a thing. It’s not possible to “run an object”, is it?

The answers to these questions are intertwined. Let’s start untwining.

### An object “as a function”

No, you can’t issue a command to “run an object” in the same sense that you can issue a command to run a function. An object has methods, though, and those methods you can invoke.

So what’s going on in `myVector(index)`? The answer lies in how the Scala language assigns a special meaning to the name `apply`.

An expression where an object reference is directly followed by a parameter list is interpreted as a call to the object’s `apply` method. For instance, `myVector(index)` is an abbreviated form of the actual command `myVector.apply(index)`.

The same works for `String`s: `"llama".apply(3)` and `"llama"(3)` both mean the same thing and return the character `m`.

In fact, this is a general rule that doesn’t require vectors, strings, or any other specific type. If an object — any object — has a method named `apply`, then that method serves as a “default method” for that object: if you leave out the dot and the name, the object runs the default method.

Another way to think about this is that an `apply` method lets you use an object “as though it was a function”. Bear in mind, though, that calling `myObject(params)` actually instructs the object to run its `apply` method, not to run the entire object in some more generic sense. An object is not actually a function; this is just a shorthand for a method call.

### Examples of `apply` methods

The `apply` methods on different classes do different things. The example you already saw is the `apply` on vectors, strings, and other collections in the Scala API. The API creators have deemed it convenient that we can access an element in a collection by writing simply `myCollection(index)`, so they’ve named that method `apply`.

You can write an `apply` method on any class or singleton object. As you do so, you’re free to choose what parameters the method takes and how it behaves. Here’s a simple example:

```object myObject:
def apply(word: String, another: String) =
println(word + ", " + another + "!")
```

Now both `myObject.apply("Ave", "Munde")` and `myObject("Ave", "Munde")` call the `apply` method to print out a greeting.

In O1, you generally won’t need to write `apply` methods of your own. Even so, it’s good to be aware of the concept so that you know what’s going on when you use vectors and strings and the like. This knowledge can also help you decipher error messages.

Suppose you have a variable `x` with the type `Vector[String]`. It stores a reference to a vector object that contains at least one element. Think about the following claims, experiment in the REPL as needed, and select all the correct ones.

## Companion Objects, or “Treating a Class as an Object”

Let’s turn to another subject. (`apply` will resurface while we discuss this new topic, though.)

### An example class

Say we’re creating a class `Customer` and intend to number the class’s instances so that every instance is associated with a unique positive integer number.

The pseudocode below outlines a solution that resembles how many beginner programmers first attempt to solve this problem.

```class Customer(val name: String):

Use a stepper variable createdInstanceCount to record how many customers exist; initially 0.
When a new customer is created, increment the stepper by one.
val number = the stepper’s value; that is, the number of instances so far

override def toString = "#" + this.number + " " + this.name

end Customer```

Here is a Scala equivalent of the pseudocode:

```class Customer(val name: String):

private var createdInstanceCount = 0
this.createdInstanceCount += 1
val number = this.createdInstanceCount

override def toString = "#" + this.number + " " + this.name

end Customer
```

However, when we use this class, it doesn’t do what we intended. Consider the code and the following animation of its execution to figure out what the problem is.

Which of the following claims about our example class are correct? Select all that apply. We intend for `number` and `createdInstanceCount` to work as discussed above.

### Attributes at the class level

Since Chapter 2.3, we’ve been fostering the idea that a class describes the data type of a particular sort of objects. A class defines the attributes that its instances have; each object has its own copies of the instance variables defined on the class. Which is precisely why our attempt at numbering the customers failed.

Sometimes, we want to associate attributes or operations with the general concept that a class represents. That is, we want to attach a variable or a function to the class itself rather than every instance of the class separately. Our customer counter is just such a variable: although each customer instance has its own number, the total number of instances is not an attribute of any of the individual instances but the class as a whole.

We would like our customer example to work more like this:

We’d like to manipulate the class as if it, too, was an object — not one of the customer objects but an object that represents the general concept of customer and that provides the single counter variable we need.

In Scala, a class is not actually an object as such and cannot be used quite as illustrated above. What we can do instead is give the class a “friend” that is an object and enables us to implement the above algorithm.

### Exposed: Intimate relationship between class and object

Here is a version of the program that works:

```object Customer:
private var createdInstanceCount = 0
end Customer

class Customer(val name: String):

Customer.createdInstanceCount += 1
val number = Customer.createdInstanceCount

override def toString = "#" + this.number + " " + name

end Customer
```

In addition to the class `Customer` we define a companion object (kumppaniolio) for the class. A companion object is a singleton object that has been given precisely the same name as a class and that is defined in the same file with that class.

The companion object `Customer` is not an instance of the customer class like the objects you create with `Customer(name)` are. The companion object’s type is not `Customer`! The companion object is a distinct object whose attributes are associated with the `Customer` concept in general.

The companion object `Customer` has the variable `createdInstanceCount`. Only a single copy of this variable exists in memory, since the customer object is a singleton (see animation below). This contrasts with the names and numbers of the various customer instances. Similarly, the counter is initialized to zero just once when the companion object is created.

We specify that whenever we create a new object of type `Customer`, we increment the companion object’s `createdInstanceCount` variable by one, then copy its new value in the customer object’s instance variable `number`.

The `Customer` class and its companion object are “friends” and have access to each other’s private members.

As noted, companion objects are singleton objects. More generally, we can say that all of Scala’s singleton objects are either:

1. companion objects, which share a name with a class defined in the same file; or

2. standalone objects, which have no class as a companion but serve some other purpose in the program.

Nearly all the singleton objects that you’ve seen in O1 so far have been standalone objects.

For an additional example of a companion object, take a look at `StarCoords.scala` in the Stars module.

### Methods in a companion object

You can define methods on a companion object just as you can define methods on any singleton. Just to illustrate the point, let’s add a method to our companion object:

```object Customer:

private var createdInstanceCount = 0

def printCount() =
println("So far, " + this.createdInstanceCount + " customer objects have been created.")

end Customer
```

Now we can write `Customer.printCount()` to print out the report.

The type of a companion

As noted, a companion object isn’t an instance of the class whose companion it is and doesn’t have the data type defined by that class.

Like other singleton objects (Chapter 2.3), each companion object has its own data type that isn’t shared by any other object. The REPL session below illustrates the difference between the types of `Customer` instances and the `Customer` companion object.

```Customer("Eugenia Enkeli")res3: Customer = #1 Eugenia Enkeli
Customer("Teija Tonkeli")res4: Customer = #2 Teija Tonkeli
Customerres5: Customer.type = Customer\$@185ea23
```

`Customer` is the type of all the instances of class `Customer`.

`Customer.type` is the type of class `Customer`’s companion object (and no other object).

`static`?

To readers who have previously programmed in Java or related languages: the variables and methods that are defined as `static` in those languages are often defined in singleton objects (and companion objects especially) in Scala. In Scala, you have no need for (and the language does not provide) a `static` modifier.

### Uses for companion objects

An instance counter for a class is a classic introductory example that serves to clarify the basic concept of a companion object. Here are a couple of other uses for companion objects that are more common in practice:

1. Constants: a companion object is a nice place for storing constants. Many constants pertain to a class in general and are not instance-specific. For example, the `StarCoords` companion object defines the constants `MinValue` and `MaxValue` that represent the edges of the coordinate system (-1.0 and +1.0).

2. Auxiliary functions: Sometimes, you’ll want to define a function that’s associated with a class but isn’t a method on the class’s instances. In such cases, you can write the function as a method on the class’s companion object. The companion object will then serve as a convenient place for keeping auxiliary functions that are related to the class. Those functions may be public or — if intended to be used by the class alone — private.

It’s never absolutely necessary to define a companion object, in the sense that one couldn’t make a program work without one. But for the above use cases, companions provide a nice, clean solution. Many classes in the Scala API have a companion object.

## Bonus Material

The remaining topics in this chapter aren’t important for O1 or indeed for learning to program in general, but they are occasionally useful when programming in Scala.

Using a singleton object as a package

Scala lets us `import` methods — and variables, too — from an object. Let’s try it:

```object toolkit:
def sumOfThree(a: Int, b: Int, c: Int) = a + b + c
val Greeting = "Ave!"// defined object toolkit
import toolkit.*```

That `import`s the contents of the `toolkit` singleton. With that done, we can access those methods and variables without mentioning the object’s name, as shown below.

```sumOfThree(100,10,1)res6: Int = 111
Greetingres7: String = Ave!
```

Now the `sumOfThree` call, for example, doesn’t look like we’re calling a singleton object’s method. We invoke `sumOfThree` as if no target object was involved at all.

Every now and then, you may find it convenient to define such a “package-like” singleton object, which is meant to be `import`ed from and which contains an assortment of methods that are more or less related to each other and .

`println`, `readLine`, and "package-like" objects in the Scala API

The familiar `println` function is actually a method on a singleton object named `Predef`. This one particular object has an elevated status in Scala: its methods can be called in any Scala program without an `import` and without an explicit reference to the object.

As for `readLine`, you learned to use it in Chapter 2.7 by first `import`ing `scala.io.StdIn.*`. As you did that, you essentially used a singleton object named `StdIn` as a “package-like object”.

`import`ing just about anywhere

In the ebook’s examples, we have generally placed any `import` statements at the top of the Scala file. This is a common practice.

Scala also lets you `import` locally within a particular class or object or even an individual method:

```import myPackage1.*

class X:
import myPackage2.*

def myMethodA =
// Here, you can use myPackage1 and myPackage2.

def myMethodB =
import myPackage3.*
// Here, you can use myPackage1, myPackage2, and myPackage3.

end X

class Y:
// Here, you can use myPackage1 only.
end Y
```

Such local `import`s sometimes make code easier to read.

`import`ing from an instance

As noted above, you can use a singleton object like a package and `import` its methods. As a matter of fact, you can even do the same to an instance of a class, if you’re so minded.

```class Human(val name: String):
val isMortal = true
def greeting = "Hi, I'm " + this.name// defined class Human
val soccy = Human("Socrates")soccy: Human = Human@1bd0b5e
import soccy.*greetingres8: String = Hi, I'm Socrates
```

The last command issued above is actually a shorthand for `soccy.greeting`.

In most cases `import`ing from instances like this is liable to make your code harder to read.

Object creation in Scala and the `new` keyword

This box contains some further details concerning how instantiation works behind the scenes in Scala. Feel free to skip this box entirely, but you could take a look in case you happen to be interested in this topic or if you happen to know the `new` keyword from some other language and are wondering about whether you need it in Scala, too.

In some other programming languages, the `new` keyword is routinely used for creating objects. For example, if we had a class `Animal`, we’d instantiate it like so:

```new Animal("llama")
```

But in Scala, we’re used to writing this shorter command instead:

```Animal("llama")
```

As it happens, the first command with `new` also works in Scala, and `new` is one of Scala’s reserved words. The meaning of the word is to instantiate a class to produce a new object. However, we don’t (almost ever) need to write `new` in our Scala code. Why not?

Behind the scenes, Scala works as follows. Let’s say you’ve written this code:

```class Animal(val species: String)
```

That defines a class for you, but what it also does, implicitly, is define a companion object for the class and an `apply` method on that companion object. That companion looks like this:

```object Animal:
def apply(species: String) = new Animal(species)
```

The generated object has an `apply` method that corresponds to the class’s constructor parameters. Internally, the `apply` method instantiates the class using the `new` keyword.

That auto-generated companion object does not show up in the code you write but exists just the same. If it didn’t exist, we’d need to write `new Animal(...)` to instantiate class `Animal`. The companion and its `apply` method mean that `Animal.apply(...)` and `Animal(...)` work equally well. The latter is the simplest and most common way to instantiate a class. (That holds from Scala’s version 3 onwards. In older language versions, it was much more common to type `new`.) Some more information: Universal Apply Methods.

One further detail: Such an auto-generated `apply` method has one more word in front of `def`. That word, `inline`, isn’t strictly necessary here but it does improve the code’s runtime efficiency. An inlined method doesn’t get allocated a frame on the call stack like other methods do. Instead, any code that calls the method, such as `Animal(...)`, basically gets replaced by the method body, `new Animal(...)`, which happens before the program even runs. For a more general discussion of this topic, see the Wikipedia article for Inline expansion.

## Summary of Key Points

• In Scala, any method named `apply` will work as a “default method” of sorts: the call `myObject(params)` automatically expands to `myObject.apply(params)`.

• In effect, an object with an `apply` method can be used “as though it were a function”.

• This technique has been used in Scala’s `String` and `Vector` classes, among others. They have `apply` methods that return whichever element is stored at a particular index.

• Sometimes you need to represent an attribute or operation that isn’t associated with each instance of a class but the class itself. To that end, you can define a so-called companion object for the class.

• A companion object is often a good place for storing constants associated with the class, for example.

• A class and its companion object can access each others’ private members.

• Links to the glossary: `apply`; companion object.

## 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, Joonatan Honkamaa, Antti Immonen, Jaakko Kantojärvi, Niklas Kröger, Kalle Laitinen, Teemu Lehtinen, Jaakko Nakaza, Strasdosky Otewa, Timi Seppälä, Teemu Sirkiä, Anna Valldeoriola Cardó, and Aleksi Vartiainen.

The illustrations at the top of each chapter, and the similar drawings elsewhere in the ebook, are the work of Christina Lassheikki.

The animations that detail the execution Scala programs have been designed by Juha Sorva and Teemu Sirkiä. Teemu Sirkiä and Riku Autio did the technical implementation, relying on Teemu’s Jsvee and Kelmu toolkits.

The other diagrams and interactive presentations in the ebook are by Juha Sorva.

The O1Library software has been developed by Aleksi Lukkarinen and Juha Sorva. Several of its key components are built upon Aleksi’s SMCL 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...