This course has already ended.

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 ohjelmaprojektien koodissa englanninkielisiä nimiä kurssin alkupään johdantoesimerkkejä lukuunottamatta.

Voit vaihtaa kieltä A+:n valikon yläreunassa olevasta painikkeesta. Tai tästä: Vaihda suomeksi.


Chapter 3.1: Interfaces and Documentation

About This Page

Questions Answered: How can I find out how to use a library class that I need? How can I help the users of my class to use it right? How do I indicate that a particular variable is for a class’s internal use only?

Topics: Public vs. private; interface vs. implementation; information hiding. Documentation and Scaladoc. The Scala API documentation.

What Will I Do? Read, mostly.

Rough Estimate of Workload:? A couple of hours.

Points Available: A10.

Related Projects: IntroOOP, FlappyBug.

../_images/person05.png

Introduction: The Interface of an Object

We have already discussed abstraction in Chapters 1.6 and 2.1. It has come up that each object has a “façade”: an abstraction through which we use the object. Let’s return to this topic and introduce some terminology that helps us talk about it.

Private vs. public

Some features of an object are public (julkinen) in the sense that those features are accessible to other parts of the program. A course object, for example, can have a public enrollStudent method that any other object can call. You use an object through its public parts.

On the other hand, some aspects of an object are private (yksityinen). In particular, the way that objects of a particular class operate is private to that class. For example, the exact details of what course objects do as they are commanded to enroll a student is private to those objects. As another example, the parrot object of Chapter 2.1 chose its reply with a private algorithm that is defined internally for that object.

Interface vs. implementation

An object’s public features constitute its interface (rajapinta). Its private features, on the other hand, form the object’s implementation (toteutus), which the interface relies on.

We can similarly speak of the interface and implementation of a class: a class prescribes the interface and implementation of each of its instances.

The user of a class or object needs to know its interface. In contrast, under normal circumstances, the user does not need to know the implementation. This is just as with other technology: What does the user of a television set need to know in order to use it? What is the interface of a TV? Does even a professional TV engineer want to think about the internal workings of their TV while flipping channels on their couch?

Just like knowing about how a TV or car works may help you sort out a problem with those devices, knowing about an implementation may help you the programmer fix a buggy program component. Even so, you don’t constantly need to think about the implementation of each component you use. Even the person who implemented a particular component will often find it useful to temporarily “forget” about its internals so that they can focus on using the component as a part of a larger whole.

Building large-scale software requires multiple programmers, each immersing themselves in the implementation of some but not all of the components that they work with. However, each programmer must know how to interface the components that they implement with any related components built by others.

Distinguishing between interface and implementation is fundamental to programming and other technological disciplines. In programming, this idea goes by the name of information hiding (tiedon piilottaminen): the implementation details of a program component (such as an object) are, in a sense, “hidden” from the programmer who uses the component.

All the topics in this chapter tie in with the central theme of information hiding, one way or another.

Side note: user interfaces

Within a program, components such as classes have interfaces. Those interfaces are meant for programmers to use.

What we call a user interface is the external interface of an entire application. It is used by the application’s end user. The program code as a whole implements the user interface.

Class Documentation

You’ve already seen first-hand that software libraries provide components for building applications. In the case of object-oriented programming, libraries tend to contain classes.

The most obvious way to learn to use a library class is to read the program code that defines it. However, that’s not always a feasible option, and often not the easiest. After all, as a class’s user, you need to know only what concept the class represents and what you can do with it; that is, you need to know the public interface, not the implementation.

It’s both common and practical to describe interfaces as documentation that is distinct from the program code and meant only for humans to read. Such documents can be published as web pages, for example.

Documenting a Scala class

A bit further down, you’ll find documentation for an example class, namely class Employee from Chapter 2.3. At this stage of O1, you don’t have to understand every detail in the document, but much of it is understandable:

  1. The page describes the class Employee. There’s a short English overview of the class below the document title.
  2. The Instance Constructors section tells you how to create an employee: what constructor parameters do you need? Each parameter is listed along with its type and a short description in English.
  3. Under Value members, there’s an alphabetical list of all the variables (val and var) and methods (def) that Employee objects have. Each item is accompanied by information that you need to know in order to use it.
  4. On the right is a menu where you can choose to view another part of the project that is documented with a similar page. In this case, there are pages available for the classes Customer and Order.

Did you notice the document’s entire contents ? Note that you can click many of the method names to expand the descriptions, sometimes considerably. We will expect you to remember this in many future assignments.

Return values in class documentation

In Scala, the programmer can choose not to write the data types of many variables and return values (Chapter 1.8). A class’s documentation nevertheless explicitly states those types.

Which is great, because the types are part of the class’s public interface and if you see them in the documentation, you’ll have an easier time using the class.

Even methods that return Unit (i.e., “return nothing”; Chapter 1.6) have been annotated with a return type in the docs. See raiseSalary in class Employee, for example.

Scaladoc

Many programming languages come with an auxiliary program that automatically generates documentation from program code and comments embedded in the code. In the case of Scala, this utility is called Scaladoc, and the documents that it generates are commonly known as “Scaladocs”.

The Scala API and its documentation

As you know, Scala has a standard library that defines data types such as Int and Double, mathematical functions such as max and min, collections such as Buffer, and much more besides. These tools, collectively known as the Scala Standard Library API or just the Scala API (from Application Programming Interface), are documented as Scaladocs here:

The Scala API consists of many packages that contain many, many classes and singleton objects. Unfortunately, parts of the API’s documentation aren’t easy for a beginner to decipher. The Scaladocs describe even some of the more common tools in a way that’s better suited to the experienced reader. In O1, we’ll cover selected parts of the Scala API; with experience, you’ll be able to work with the API documentation more productively on your own.

Creating your own Scaladocs

In O1, you need to only read Scaladoc pages, not author your own. Even so, you may wish to learn how the documents have been created.

The first step is to record information about your program in documentation comments that start with /** (instead of the /* or // that starts an ordinary comment). For example, to document monthlyCost in class Employee, we might write:

/** Returns the monthly cost of the employee to the employer. This figure equals
  * the product of the employee's monthly salary (e.g., 4000), their working time
  * (e.g., 0.6), and a multiplier for incidental costs (e.g., 1.3).
  *
  * @param multiplier  a multiplier used by the employer to estimate the additional
  *                    costs of employing a person, apart from their salary */
def monthlyCost(multiplier: Double) = this.monthlySalary * this.workingTime * multiplier

We can then give this program code as input to the auxiliary program Scaladoc, which generates an HTML document like the one displayed above on this page. For more information on the Scaladoc tool, see Alvin Alexander’s tutorial.

Scaladocs in O1’s projects

O1Library’s key classes, such as Pic, Pos, and View, are described as Scaladocs in the doc folder within that project. You can use either Eclipse or an external web browser to open these documents.

There is a similarly-named doc folder in project IntroOOP and in many of the other projects that you’ll encounter; however, not every project in O1 has Scaladocs. You can also access these documents online through the “Related Projects” link at the top of each chapter.

Adjusting Visibility

Problem: a poorly defined interface

Here, again, is class Order from Chapter 2.6.

class Order(val number: Int, val orderer: Customer) {

  var totalPrice = 0.0   // gatherer

  def addProduct(pricePerUnit: Double, numberOfUnits: Int) = {
    this.totalPrice = this.totalPrice + pricePerUnit * numberOfUnits
  }

  // ...
}
Recall: totalPrice is a var that’s meant for storing the sum of the prices of all the added products.
The variable’s value should change only when addProduct is called.

If that is our goal, we haven’t quite met it. That’s because our class allows an operation that we didn’t mean to be possible: the class’s user can assign any arbitrary value to the instance variable: testOrder.totalPrice = 123456. Such a command will discard the old value and ignore the prices of any and all products that may have been added earlier.

In other words, our class’s public interface provides the option of assigning directly to totalPrice even though we don’t actually intend for the class’s user to do that. Our intent was to control the variable within the class’s internal implementation.

Perhaps you recall a similar concern from Chapter 2.2, which we acknowledged then but didn’t solve: it was possible to assign any value, even a negative one, to the account object’s balance without calling withdraw or deposit. The account object, too, gave its user the opportunity to do something that went against the object’s overall design.

Solution: the private modifier

We can turn the instance variable that gathers the price into a private member of the class. What this means in practice is that we can still update the variable within Order’s program code but nowhere else.

This revised version is a step in the right direction even if it doesn’t quite do everything we want yet:

class Order(val number: Int, val orderer: Customer) {

  private var totalPrice = 0.0   // gatherer

  def addProduct(pricePerUnit: Double, numberOfUnits: Int) = {
    this.totalPrice = this.totalPrice + pricePerUnit * numberOfUnits
  }

  // ...
}
We add the word private where we define the instance variable.

Because we made the variable private, any external attempt to assign to sumOfPrices will fail:

testOrder.totalPrice = -100<console>:9: error: variable totalPrice in class Order cannot be accessed in o1.classes.Order
     testOrder.totalPrice = -100

In that respect, all is well, but now this is a problem:

println("Price in total: " + testOrder.totalPrice)<console>:9: error: variable totalPrice in class Order cannot be accessed in o1.classes.Order
     println("Price in total: " + testOrder.totalPrice)

From outside the class, we can’t even examine the value of a private variable. Nevertheless, we’d like the users of class Order to be able to access the order’s total price (even though they can’t assign arbitrary values to it). Fortunately, this is easily fixed:

A private variable with a public method

This version of the class works as we intended:

class Order(val number: Int, val orderer: Customer) {

  private var sumOfPrices = 0.0     // gatherer

  def totalPrice = this.sumOfPrices

  def addProduct(pricePerUnit: Double, numberOfUnits: Int) = {
    this.sumOfPrices = this.sumOfPrices + pricePerUnit * numberOfUnits
  }

  // ...
}
We also change our private variable’s name from totalPrice to sumOfPrices, because...
... we now define a method named totalPrice (note the def). This simple method merely returns the current value of sumOfPrices.

Now we can call the method (e.g., testOrder.totalPrice) to make an order object tell us its price, even though we can’t assign new values to the variable that tracks the price. The attempted assignment testOrder.totalPrice = -100 gives an error, because in our new implementation, totalPrice is no longer a variable but a parameterless method.

The same solution works for the account object: you can use a private variable to track the balance and add a public method. (Optional assignment: make it so.)

Interfaces and private

The above example illustrates that private variables aren’t part of a class’s public interface but belong to the implementation. For the same reason, private variables are not listed in Scaladocs whose purpose is to provide an external view of using the class.

For example, the name sumOfPrices doesn’t feature in the Scaladocs for Order. From the user’s point of view it’s irrelevant which name the class’s implementor has chosen for the variable or indeed that the variable exists in the first place. What the user wants to do is access the public methods totalPrice and addProduct and the public variables number and orderer.

As we noted in Chapter 2.2, if no-one ever makes the mistake of assigning an inappropriate value to an object’s variable, perhaps there is no problem. But it makes sense to minimize opportunities for mistakes. The private modifier doesn’t prevent the class’s creator from making a mistake while implementing the class, but once they do their job right, nobody (not even themselves!) can inappropriately assign to the private variable as they use the class.

A quick word about private methods

It’s perfectly possible and often useful to define methods that are private and intended only for the internal use of a class or singleton object. You’ll see examples in many later chapters (e.g., 3.5).

Assignment: FlappyBug (Part 9 of 16: Private Variables)

When we use a var variable to represent an object’s changing state, we’d often like to exercise a measure of control over how and when the variable’s value changes. Our order and account examples are two cases in point, and there are still more uses for private variables in the programs that you’ve already seen. Consider the FlappyBug game, for instance:

A small change to Obstacle

In Week 2, we wrote this version of class Obstacle:

class Obstacle(val radius: Int, var pos: Pos) {

  def approach() = {
    this.pos = this.pos.addX(-ObstacleSpeed)
  }

  override def toString = "center at " + this.pos + ", radius " + this.radius
}
We intend for the approach method, and it alone, to govern the obstacle’s motion. No other party should assign to the instance variable that stores the obstacle’s position.
The variable pos is a var, and public. However, we don’t intend to give the class’s user the option to “teleport” an obstacle to an arbitrary location by assigning to pos. So let’s not.

Here’s a revised definition:

class Obstacle(val radius: Int, initialPos: Pos) {

  private var currentPos = initialPos

  def pos = this.currentPos

  def approach() = {
    this.currentPos = this.currentPos.addX(-ObstacleSpeed)
  }

  override def toString = "center at " + this.pos + ", radius " + this.radius
}
A constructor parameter. Note the absence of val. If you add val in front, this becomes an instance variable (and a public one at that).
A private instance variable.
A public method that the class’s user can use to determine an obstacle’s position.
Now the only way to move an obstacle is to call approach on it, as intended.

Task description

  1. In your copy of FlappyBug, edit Obstacle as shown above. (If you didn’t do the earlier FlappyBug assignments, study them now. After each deadline, links leading to example solutions are published within the chapters.)
  2. Change Bug in the same way: store the bug’s position in a private variable. Provide a public method named pos that returns that variable’s value.
    • After the changes, the only way to move a bug is to call fall or flap (which make sure the bug stays within bounds!).
    • That is, your class must no longer have a public var named pos.
    • Also make sure you don’t have any additional public members in your class beyond those specified. For example, there mustn’t be a public variable named initialPos.
  3. In Chapter 2.8, you defined a variable yVelocity. Prevent its value from being arbitrarily changed by turning it private.
    • Since the user of Bug doesn’t actually need to use the bug’s velocity for anything, it suffices to add the private modifier to the variable. You don’t need a public method for accessing the value stored in the variable.

Submission form

A+ presents the exercise submission form here.

Can you find more?

Going back to the programs you’ve seen so far, can you find more instance variables that you might wish to make private?

Look at class Counter, for example.

Questions to think about

In the examples above, all the private variables were vars. Is this coincidence? Do vals and vars differ from each other in this respect?

Why is there no need to make anything private in, say, the Pos class of Chapter 2.5?

When might one want to define a private val?

We’ll return to some of these topics in Chapter 3.6.

Summary of Key Points

  • Classes and singleton objects can be described as documents that tell the programmers that use them what they need to know.
    • Scala’s standard library and O1’s own library have been described in this fashion as Scaladoc documents.
  • You can make parts of a class private. A private variable is meant for internal use within that class only.
  • Links to the glossary: public, private, interface, implementation, information hiding, abstraction; documentation, Scaladoc, API.

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!

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 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 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.

../_images/imho3.png
Posting submission...