6
\$\begingroup\$

I'm following this presentation. At the very end there's an exercise about solving Fibonacci and says that instead of addition, make the operation setteable by a function.

Is the following is a good solution? How close might it be to what Rob Pike would have written?

package main

import "fmt"

func add(a, b int) int {
    return a + b
}

func subtract(a, b int) int {
    return a - b
}

func power(a, b int) int {
    return a ^ b
}

// fib returns a function that returns
// successive Fibonacci numbers.
func fib(op func(int, int) int) func() int {
    n0, n1 := 0, 1
    return func() int {
        n0, n1 = n1, op(n0, n1)
        return n0
    }
}

func main() {
    f := fib(add)
    // Function calls are evaluated left-to-right.
    fmt.Println(f(), f(), f(), f(), f(), f(), f())

    f = fib(subtract)
    // Function calls are evaluated left-to-right.
    fmt.Println(f(), f(), f(), f(), f(), f(), f())

    f = fib(power)
    // Function calls are evaluated left-to-right.
    fmt.Println(f(), f(), f(), f(), f(), f(), f())
}
\$\endgroup\$
0
6
\$\begingroup\$

This seems like a good solution except for one thing:

func power(a, b int) int {
    return a ^ b
}

The ^ operator doesn't do what you think it does. It's a bitwise xor operator. There is no power operator in Go, there's only math.Pow for float64s.

On a side note, I personally would create a type for operators:

type Op func(int, int) int

It's easier to type in function definitions and allows you to extend it with methods like String().

\$\endgroup\$
0
\$\begingroup\$

It looks like you figured out what he was referring to with getting the next value in the sequence without global variables or structs.

The slides ask you to write tests which is a wise. Had you written some expectations of what the your power function was supposed to do it would of illustrated that it is incorrect. You are using the bitwise xor operator on your arguments which is not exponentiation.

You can create a file aside your implementation named <your_file_name>_test.go with various tests defined inside like the one below. Each func TestYouTestName(t *testing.T) {} defined within this file will run with the go command go test ./....

func TestPowerOperation(t *testing.T) {
    cases := []struct{
        a, b, want int
    }{
        {  1,   1, 1},
        {  2,   2, 4},
        {  2,   3, 8},
        {  0, 100, 0},
        {100,   0, 1},
    } 

    for _, c := range cases {
        got := power(c.a, c.b)
        if (c.want != got) {
           t.Error("Expected power(%d, %d) == %d; got %d", c.a, c.b, c.want, got)
        }
    }
}

This example creates five (non exhaustive) test cases that are run with the power function you defined. When you run the test runner you will see that the test will fail as your implementation is not correct. Testing is a great way to confirm that what you expect to happen will.

\$\endgroup\$
3
  • \$\begingroup\$ Sorry, but what does this add over the two-weeks-old accepted answer? \$\endgroup\$ – Deduplicator Oct 16 '15 at 16:55
  • \$\begingroup\$ It was my intent illustrate the value of tests. I can edit to include an example. \$\endgroup\$ – Ben Campbell Oct 16 '15 at 17:45
  • \$\begingroup\$ That would be a good idea. \$\endgroup\$ – Deduplicator Oct 16 '15 at 20:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.