17. Boolean logic in depth — Homework solutions

The .go solution files are in exercises/17/homework/solutions/.

Problem 1 — Default colour

Problem. Fall back to "blue" when fav is empty.

How to think about it. Start colour with the value of fav. Replace it only when it is "".

Worked solution.

package main

import "fmt"

func main() {
    fav := "" // try a real colour too

    colour := fav
    if colour == "" {
        colour = "blue"
    }

    fmt.Println("Your colour is " + colour)
}

With fav := "" it prints:

Your colour is blue

With fav := "red" it prints:

Your colour is red

Common mistakes.

  • Writing colour := fav || "blue". || only works on bools, so Go stops with an operator || not defined error.
  • Writing if fav {. A string is not a bool. The test is fav == "".
  • Declaring colour with := inside the if. It then disappears at the closing }, as Chapter 16 showed.

Problem 2 — Say what you mean

Problem. Show whether each value differs from its zero value.

How to think about it. The test depends on the type: != 0 for an int and != "" for a string. A bool is already an answer, so isReady needs no comparison at all.

Worked solution.

package main

import "fmt"

func main() {
    count := 0
    name := ""
    isReady := false
    greeting := "hi"
    level := 1

    fmt.Println(count, count != 0)
    fmt.Printf("%q %v\n", name, name != "")
    fmt.Println(isReady, isReady)
    fmt.Printf("%q %v\n", greeting, greeting != "")
    fmt.Println(level, level != 0)
}

Output:

0 false
"" false
false false
"hi" true
1 true

Common mistakes.

  • Writing count by itself as the test. It prints the number, not a bool.
  • Comparing across types, like name != 0. That is a mismatched types error.

Problem 3 — Guarded division

Problem. Print the average only when it can be worked out and is over 20.

How to think about it. count > 0 goes first, so total/count never runs when count is 0. The comparison uses whole number division, which is good enough to test against 20. The printed average needs decimals, so both numbers are converted to float64, as in Chapter 13.

Worked solution.

package main

import "fmt"

func main() {
    total := 90
    count := 0 // try 3 and 10 too

    if count > 0 && total/count > 20 {
        average := float64(total) / float64(count)
        fmt.Printf("High average: %.2f\n", average)
    } else {
        fmt.Println("no high average")
    }
}

With count := 0, the count > 0 test is false, so Go skips the division and prints:

no high average

With count := 3 it prints:

High average: 30.00

With count := 10, the average is 9, so it prints no high average again.

Common mistakes.

  • Writing total/count > 20 && count > 0. The division now runs first, and with count at 0 the program crashes with panic: runtime error: integer divide by zero.
  • Printing total / count with %.2f. That is an int, so the output is %!f(int=30). Convert both numbers first.

Challenge — First value that exists

Problem. Print the first of a, b, c that is not empty.

How to think about it. A switch with no value runs the first case whose condition is true, and that is exactly the question. default handles the case where all three are empty.

Worked solution.

package main

import "fmt"

func main() {
    a := ""
    b := ""
    c := "third"

    switch {
    case a != "":
        fmt.Println(a)
    case b != "":
        fmt.Println(b)
    case c != "":
        fmt.Println(c)
    default:
        fmt.Println("none")
    }
}

Output:

third

Common mistakes.

  • Using separate if statements with no else. Every non-empty variable then prints, not just the first.
  • Forgetting default, so nothing prints when all three are empty.

Done?

You now know that && and || take bools and give a bool, that they short-circuit, and that a default value comes from an explicit comparison. Next is Loops, the other way to make a program do more than the same thing each time.