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.1: Logic, Blood, and Shopping

Questions Answered: How do I write “If either that or that condition is met?” Or “If both conditions are met?” Can I write Scala classes independently already?

Topics: Logical operators are new. The programming assignments combine assorted earlier topics.

What Will I Do? Program, mostly. There’s a bit of reading at the beginning.

Rough Estimate of Workload:? Two or three hours? And quite a bit more if you do all the optional assignments, too.

Points Available: A120.

Related Modules: FlappyBug, Miscellaneous, Blood (new), AuctionHouse1 (new).

## Intro: Let’s Make FlappyBug Harder

In Chapter 3.3, you wrote `isLost`, a method that defines a `Game` of FlappyBug to be over if the obstacle touches the bug.

```def isLost = this.obstacle.touches(this.bug)
```

Recap: `touches` returns `true` or `false`. Consequently, `isLost` also returns one of the two `Boolean`s.

As things stand, it’s too easy for the bug to advance simply by lurking at the top or bottom. Let’s edit `touches` so that the player loses if an obstacle hits or or the bug is at the top or bottom of the playing area.

Here’s one way to do it:

```def isLost =
if this.obstacle.touches(this.bug) then
true
else if this.bug.pos.y <= 0 then
true
else
this.bug.pos.y >= GroundY
```

The game is lost if the bug hits an obstacle.

Or if it didn’t hit an obstacle but is too high.

Or if it isn’t too high either but is too low.

That works. But it’s a complicated way of expressing something rather simple. We’d much rather write “if that condition or that other condition is met.” Perhaps you’ve already yearned after such an expression in the earlier chapters.

In this chapter, you’ll learn to combine `Boolean` values with logical operators such as “and” and “or”. We’ll get back to FlappyBug after a general introduction to these operators.

## Logical Operators

The Scala language supplies us with several logical operators (logiikkaoperaattori).

Operator

Name

Example

Meaning

`&&`

and

`someClaim && otherClaim`

“Are both Booleans `true`?”

`||`

or

`someClaim || otherClaim`

“Is at least one of the Booleans `true`?”

`^`

exclusive or (xor)

`someClaim ^ otherClaim`

“Is exactly one of the Booleans `true`?”

`!`

not (negation)

`!someClaim`

“Is the Boolean `false`?”

In O1, you’ll mostly find use for `&&`, `||`, and `!`. The last of those you already know from earlier chapters.

The logical operators take in `Boolean` values and also produce `Boolean`s:

```val number = 50number >= 0 && number <= 5res0: Boolean = false
if number >= 0 && number <= 5 then "a valid grade" else "an invalid grade"res1: String = "an invalid grade"
number == 100 || number == 50res2: Boolean = true
!(number >= 0)res3: Boolean = false
```

The “and” operator `&&` produces `true` if and only if both subexpressions are `true`. Here, the first subexpression is `true` but the second isn’t, so the whole expression evaluates to `false`.

The “or” operator `||` produces `true` if either of the two subexpressions is `true` (or both are). Here, the first subexpression isn’t `true` but the second is, so the whole expression evaluates to `true`.

Terminological note: the subexpressions that an operator works on are often called operands (operandi). Of the logical operators introduced here, the negation operator `!` takes only a single operand while the others take two.

### Non-strict evaluation of logical operators

The operators `&&` and `||` are evaluated non-strictly (väljästi). What this means for these operators is essentially that the left-hand operand is evaluated first and if it alone determines the value of the logical operation, the right-hand operand isn’t evaluated at all. (We will take a broader look at non-strict evaluation in Chapter 7.2.)

This non-strictness has practical significance, as illustrated below.

First, let’s define a couple of variables. Here, we use literals, but you can easily imagine the numbers being read from the user’s keyboard, for instance.

```val dividend = 50000dividend: Int = 50000
var divisor = 100divisor: Int = 100
```

Let’s divide one number with the other and see what we get. As we do so, let’s play things safe and ensure that `divisor` doesn’t equal zero. We can use either `&&` or `||` to do that:

```divisor != 0 && dividend / divisor < 10res4: Boolean = false
divisor == 0 || dividend / divisor >= 10res5: Boolean = true
```

Assuming the divisor is not zero, we can swap the operands and still get the same result:

```dividend / divisor >= 10 || divisor == 0res6: Boolean = true
```

But what if the divisor is zero?

```divisor = 0divisor: Int = 0
dividend / divisor >= 10 || divisor == 0java.lang.ArithmeticException: / by zero
...
```

The computer performs the division as it evaluates the first operand. We get a runtime error. We never even reached the expression `divisor == 0`.

On the other hand, if we check the divisor in the first operand, things work out fine:

```divisor == 0 || dividend / divisor >= 10res7: Boolean = true
```

Since divisor equalled zero, the expression `divisor == 0` evaluated to `true`. It becomes unnecessary to evaluate the rest of the logical expression given that ```true || anythingAtAll``` is always `true`. Because of the non-strictness of these operators, the computer doesn’t even evaluate the second operand. Execution order matters!

Suppose you have the variables `divisor` and `dividend` as above and `divisor` equals zero. Below are a number of claims about the expression `divisor != 0 && dividend / divisor < 10`. Which of them are correct? Select all that apply.

### Combining logical operators

You can use rounds brackets to group logical expressions just like arithmetic and other expressions.

```if (number > 0 && number % 2 == 0) || number < 20 then
println("Either both positive and even, or less than 20.")

if number > 0 && (number % 2 == 0 || number < 20) then
println("Positive; moreover, either even or less than 20.")
```

### Practice on logical operators

Study the following piece of code. Carefully consider what happens as it runs. You might wish to make notes on a piece of paper.

```val first = 20
val second = 10
var third = 50

if first > second && first + second < third then
third = 30
println("One")

val result = first > second && first + second < third

if first < second || result then
println("Two")

if first > second || second == third then
println("Three")

third = 10

if !(result && third >= 50) then
println("Four")
else
println("Five")
```

In the second `if` above, the `||` operator in `first < second || result` has two operands. What happens when this expression is evaluated?

In the third `if` above, the `||` operator in `first > second || second == third` has two operands. What happens when this expression is evaluated?

Which lines of text do the `println` commands in the above code produce?

### Further improvements to the vending machine

Logical operators are a convenient replacement for multiple `if`s.

Recall the `sellBottle` method from Chapter 3.5. Here is the original `Int`-returning version:

```def sellBottle() =
if this.isSoldOut then
-1
else if !this.enoughMoneyInserted then
-1
else
this.earnedCash = this.earnedCash + this.bottlePrice
this.bottleCount = this.bottleCount - 1
val changeGiven = this.insertedCash - this.bottlePrice
this.insertedCash = 0
changeGiven
```

Here are two attempts to reimplement the method with logical operators:

```def sellBottle() =
if this.isSoldOut || !this.enoughMoneyInserted then
-1
else
this.earnedCash = this.earnedCash + this.bottlePrice
// Etc. As above.
```
```def sellBottle() =
if this.enoughMoneyInserted && !this.isSoldOut then
this.earnedCash = this.earnedCash + this.bottlePrice
// Etc. As above.
else
-1
```

Assess the two shorter implementations.

## Assignment: FlappyBug (Part 15 of 17: Deadly Edges)

Make FlappyBug harder as suggested at the top of the chapter. Do it as follows.

1. Add an effect-free, parameterless method `isInBounds` in class `Bug`. It should return a `Boolean` that indicates whether the bug is within the legal playing area, that is, between the zero coordinate and the ground level (excluding those border values). Use a logical operator to implement the method.

2. Modify `isLost` in class `Game` so that it also considers a game to be lost if the bug is out of bounds. Use logical operators and the `isInBounds` method you just wrote.

A+ presents the exercise submission form here.

## Assignment: Blood Types

The module Blood contains several numbered packages. For now, we’ll concentrate on `o1.blood1`. Within that package, there’s a class named `BloodType`. Implement that class so that it matches the module’s documentation.

### Instructions and hints

• This example shows how the class should work:

```import o1.blood1.*val myBlood = BloodType("AB", true)myBlood: o1.blood.BloodType = AB+
val yourBlood = BloodType("A", true)yourBlood: o1.blood.BloodType = A+
val theirBlood = BloodType("O", false)theirBlood: o1.blood.BloodType = O-
myBlood.canDonateTo(yourBlood)res8: Boolean = false
yourBlood.canDonateTo(myBlood)res9: Boolean = true
theirBlood.canDonateTo(yourBlood)res10: Boolean = true
```
• You can also run the given program (`test`) to try out all the possible combinations of blood types.

• Once again, you don’t have to attend to special cases or erroneous input unless specifically instructed to. For example, you can count on any user of class `BloodType` to pass in only meaningful strings as constructor parameters.

• Try to implement the methods as simply as you can and without duplicating the same piece of code.

• Use logical operators. Can you make do without `if` and `match` altogether (apart from`toString`)?

• Call the other methods of the same class. Further tip: you can pass `this` as a parameter to a method.

A+ presents the exercise submission form here.

## Assignment: `FixedPriceSale`

The Scaladocs in module AuctionHouse1 describe several classes for representing items that have been put up for sale in an imaginary online auction house. In this assignment, we’ll focus on a single way to sell an item: simply giving it a fixed price. Later assignments will features auctions and changing prices.

Fetch the AuctionHouse1 module and view its Scaladocs. Implement class `FixedPriceSale` of package `o1.auctionhouse` so that its behavior matches the documentation. Write your solution in `FixedPriceSale.scala`.

### Instructions and hints

• You may wish to use an instance variable of type `Option`, with an initial value of `None`. If you do, remember that you need to annotate the variable with a data type (as in Chapter 4.3). Like this: `nameOfVariable: Option[Type]`.

You should make two instance variables of the three constructor parameters. You’ll find these two public variables listed in the docs.

You’ll need a couple of more variables: one to track the number of remaining days and another to store the buyer’s name.

Since there isn’t necessarily any buyer, `Option[String]` is a suitable type for the latter variable.

The two variables just mentioned aren’t listed in the docs; they are part of the class’s internal implementation. Make them private and name them as you please.

• The Scaladocs list the class’s members in alphabetical order, but that’s probably not the most convenient order for you to implement them (nor do the methods need to be in that order in your code). You are free to choose the order in which you implement the methods, but here’s one suggestion: `toString`, `daysLeft`, `buyer`, `isExpired`, `isOpen`, `advanceOneDay`, `buy`.

Study the docs with care. Notice, for instance, that “open” and “expired” aren’t exact opposites even though an item cannot be both at the same time.

Most of the methods are effect-free. They only need to return the value of an instance variable or check whether the instance variables meet a certain condition. A single-line expression will do as the implementation for each of these methods.

Items have two effectful methods: `advanceOneDay` changes the number of days remaining and `buy` changes who’s bought the item. You should have each of those things available in instance variables. Remember, in both methods, to check whether the sale was open; you can call `isOpen` to do that.

• You may use the program `testFixedPrice` for testing. Use it.

• That program initially generates error messages, which is simply because you haven’t yet implemented the methods that the program calls. The errors will go away once you do the assignment. (Remember: the cause of an error is not always where the message points to.)

• You can initially “comment out” part of the test program if you want to test a partial version of your class.

• You can also run `TestApp`, a program in `o1.auctionhouse.gui` that lets you create and manipulate `FixedPriceSale` objects in a graphical window that looks like this:

A+ presents the exercise submission form here.

## Optional Practice: `Moment` and `Interval`

The rest of the chapter consists of practice tasks that are voluntary but highly recommended. Take them as an opportunity to build up fluency. If the weekly deadline is ominously close, you might wish to do the other chapters first before returning here. The assignments below will probably take several hours to complete.

### Introduction to `o1.time`

This problem will let you apply the logical operators more extensively and freely than the preceding ones. It also provides practice on a number of other concepts.

Moments and intervals

Imagine we have an application (or several) that needs to represent time intervals: an interval begins at a particular moment of time and continues until another moment. We intend to model these concepts as the classes `Moment` and `Interval`. Each `Interval` object is associated with two `Moment` objects that represent the interval’s first and last moment.

The Miscellaneous module contains a package `o1.time` and, therein, a partial implementation for class `Moment`. `Interval` is missing entirely.

The given code for `Moment` is explained below.

```import scala.math.abs

class Moment(private val time: Int):

override def toString = this.time.toString

def distance(another: Moment) = abs(another.time - this.time)

def isLaterThan(another: Moment) = this.time > another.time

def later(another: Moment) = if this.isLaterThan(another) then this else another

def earlier(another: Moment) = if this.isLaterThan(another) then another else this

end Moment
```

As we create a `Moment` instance, we specify the moment in time that it stands for. Our implementation doesn’t commit to any particular unit of time (days, years, nanoseconds, etc.); any integer will do.

A `Moment` delegates its whole `toString` method to the integer it stores. Notice that you can call a method on an `Int`! An `Int`’s `toString` method returns the characters that correspond to the number; e.g., for the integer 123 we get the string `"123"`. (We will discuss the methods on `Int`s further in the next chapter, 5.2.)

There’s a `distance` method for determining how far apart two moments are.

`isLaterThan`, `later`, and `earlier` compare moments in different ways.

### General hint: make use of abstractions

One of this problem’s main themes is to learn to make use of the other methods in the classes that you write. Sure, you’ve already done that in ealier assignments, too, but this one particularly highlights the matter.

If you write the required methods completely independently of each other, you’ll find yourself duplicating code. Don’t do that. Consider what other methods you’ve created that you could call. Try to keep your code DRY. Non-redundant code is easier to modify and less vulnerable to bugs.

In fancier words: Every method is an abstraction (Chapter 1.6). You should build new abstractions atop existing ones. For example, the method `isLaterThan` is as an abstraction of its concrete implementation, which takes the values of two instance variables and uses an operator to compare the two: `this.time > another.time`. The other methods that need to compare two `Moment`s can simply use this method and don’t need to deal with the variables directly.

### A task in four phases

Implement `Interval` and `Moment` so that they meet the specification. Below is a recommended workflow that you can either follow or ignore.

Phase 1 of 4: Getting started with `Interval`

1. Read the introductions of both classes in the Scaladocs. Also read the docs for `Interval`’s methods `length` and `toString`, which you’ll implement first.

2. Create a new file for class `Interval`.

3. Define the constructor parameters. Since each parameter needs to be stored in an instance variable, define those, too, in the class header. Should these instance variables be private?

4. Implement `length`. Use a method from class `Moment`.

• Now and later: resist the temptation to add public members in class `Moment` beyond those request in the docs. In particular, don’t make the instance variable `time` public.

5. Implement `toString`. It’s a bit more complicated. Here are some hints:

• Use the methods you have at your disposal.

• You can use an `if``else` structure to cover the three different cases.

• Remember that a string can be “multiplied”. For instance, `"ho" * 3` yields `"hohoho"`.

6. See the starter code in `timeTest`. Add commands there as you see fit: create `Interval` objects and call their methods.

When are two `Moment`s equal?

If you use `==` or `!=` to compare moments, what you get is an identity comparison (“Do these two references point to the same `Moment` object?”; see Chapter 3.3.) What you don’t get is a comparison of the `Moment` objects’ actual contents. These operators won’t tell you whether two distinct `Moment` objects represent the same moment in time, that is, whether their `time` variables have identical values.

In this assignment, identity comparison and those two operators are completely unnecessary. You don’t stand to gain anything from using them. Other methods will serve you better!

Phase 2 of 4: `isLaterThan` and overloading

The interval assignment was quite a tranformative experience.

I was already well on my way, writing an `if` statement in each method and not reusing methods, when a couple of formidable and eagle-eyed course assistants, who just happened to be in the room, pointed this out to me.

I didn’t dare defy the wise assistants so I racked my brain, sweating, to figure out how it could even be possible to manage without an `if`. Once I came up with a solution for `isLaterThan(Interval)` (helped by a hefty dose of hints from the assistant), I felt like I had just invented the wheel. It was ingenious!

1. Add `isLaterThan` in class `Interval`. Note that the method name has been overloaded (Chapter 4.1): there are two methods with the same name. One takes in a `Moment` and the other an `Interval`. Implement the former first. Make use of an existing method.

2. Implement the second `isLaterThan` method in `Interval`. Make use of the method you implemented just before. As you do so, remember a detail from Chapter 4.1: if an overloaded method calls its namesake, Scala requires an explicit type annotation for the calling method’s return type. That means you’ll need to annotate the type on at least one of the `isLaterThan` methods.

3. Add more test code to `timeTest` and run it. Confirm that both `isLaterThan` methods work as intended.

4. `Moment` should also have an `isLaterThan` method that takes in an `Interval` parameter. Add that method to the class.

Phase 3 of 4: logical operations

Continue implementing methods on `Interval` and `Moment`:

1. Of the two `contains` methods of `Interval`, implement the one that takes in a `Moment`. Use logical operators in combination with methods that you have previously implemented.

2. Implement the other `contains` method. Again, use logical operators and the other methods. Also recall what was just said about overloaded methods.

3. Implement `isIn` in class `Moment`. It essentially does “the same thing in reverse” as another method you already wrote, which gives you a very simple implementation for it.

4. Implement `overlaps` in class `Interval`. Once again, you can find uses for logical operators and existing methods. Make sure you cover all the possible cases.

5. Add more method calls in `timeTest` and test your new methods.

Phase 4 of 4: combining instances to produce new ones

The methods `union` and `intersection` are still missing from class `Interval`. Implement them and you’re done.

A+ presents the exercise submission form here.

## How private is `private`?

Student question: How can that `Moment` class work? `time` is private!

Let’s take a moment to consider why the given code from the previous assignment doesn’t produce an error message.

```class Moment(private val time: Int):
def isLaterThan(another: Moment) = this.time > another.time
```

`time` is `private`. It’s not available for external use. But what counts as external, exactly?

A `Moment` object can access its own `time`.

A `Moment` object can also access the `time` of another `Moment` object: we simply prefix the variable name with an expression that refers to another object of the same class. Here, that expression is the variable name `another`.

Within a class’s code, the `private` modified indicates that a member of the class is meant for internal use within that class. The private member isn’t accessible by only a single object but also by the class’s other instances; it is private to them collectively.

## Optional Practice: Auctions

Assignment: `DutchAuction`

Go back to AuctionHouse1. Implement class `DutchAuction` as specified.

Instructions and hints:

• First and foremost: make sure you understand what “Dutch auctions” are! The details are in the Scaladocs. Unless you have a clear idea of what the class should do, implementing it will be tough going.

• As you read the docs, you’ll notice that some parts of `DutchAuction` are identical to `FixedPriceSale`. You can copy parts of your earlier solution into your `DutchAuction` class.

• You can again use `TestApp` from `o1.auctionhouse.gui` to experiment with your class. You can of course also write your own text-based program for testing.

• If you have an `Int` and need a `Double`, you can either

• do what we did in Chapter 1.3: `1.0 * myInt`

• or do what we’ll do in Chapter 5.2: `myInt.toDouble`

A+ presents the exercise submission form here.

Are you a bit upset that you had to write the same methods again in class `DutchAuction` or at least copy them from one file to the other? Outstanding! That means that you’re motivated to reach Chapter 7.3 where you’ll learn about avoiding such code duplication.

Assignment: `EnglishAuction`

Stay with AuctionHouse1 and implement `EnglishAuction`.

Instructions and hints:

• Again, first make sure you understand exactly how “English auctions” are expected to work.

• A simple `Bid` has been provided, which you should find useful. There is also a bit of starter code for `EnglishAuction`.

• Even though it’s possible to solve the assignment with a buffer that stores all bids placed on an item, you don’t actually need to do that. As it turns out, you don’t need to solve every last bid to fullfill the requirements...

• Instead, you can use two variables to store just the two highest bids, as shown in the starter code. Notice these two variables’ initial values: when there are no actual bids yet, the variables refer to “empty” `Bid`s equal to the starting price.

• `TestApp` will again be of service.

A+ presents the exercise submission form here.

## Summary of Key Points

• Logical operators operate on Boolean values. You can use them to express meanings such as “X and Y” and “X or Y”.

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