Go Quiz Questions

Martin Sulzmann

Functions in Go

package main

import "fmt"

// Quiz.
// Test your Go knowledge.
// You are given some program text and have to answer questions
// by selecting the right answer.
// Solutions can be found below.

// Functions in Go

// Some example functions.

// Parameterless function, no return value.
func f1() {

}

// Single parameter, no return value.
func f2(x int) {

}

// Parameter-less function, single return value.
func f3() int {
    return 1
}

// Single parameter, multiple return value.
func f4(x int) int {
    return x + 1
}

// Multiple parameters, multiple return values.
func f5(x int, y int) (int, int) {
    return x + 1, y + 1
}

// Warm-up.
// Some (function) variables and their types.
func q1() {
    var g1 func()
    var g2 func(int)
    var g3 func() int
    var g4 func(int) int
    var g5 func(int, int) (int, int)

    g1 = f1
    g2 = f2
    g3 = f3
    g4 = f4
    g5 = f5

    g1()
    g2(1)
    fmt.Printf("\n %d", g3())
    fmt.Printf("\n %d", g4(1))
    x, y := g5(1, 2)
    fmt.Printf("\n %d %d", x, y)

    // Go supports simple type inference.

    // We introduce a nested block to avoid name clashes.
    {
        g1 := f1
        // g1 is a newly declared variable and
        // its type equals the type of the expresson
        // on the right-and side.
        // f1 is of type func() and that's also g1's type.

        g2 := f2
        g3 := f3
        g4 := f4
        g5 := f5

        g1()
        g2(1)
        fmt.Printf("\n %d", g3())
        fmt.Printf("\n %d", g4(1))
        x, y := g5(1, 2)
        fmt.Printf("\n %d %d", x, y)
    }
}

func plus(x int, y int) int {
    return x + y
}

func q2() {
    p := plus

    fmt.Printf("%d", p(1, 2))

    // What is the type of p?
    // A: int func(int, int)
    // B: func(int, int)
    // C: func(int, int) int

}

func q3() {

    // The expression "plus(1)" is not well-typed. Why?
    // A: The name of the function is misspelled.
    // B: The function lacks an additional parameter.
    // C: The input is too small.
}

func q4() {
    var f func(int, int) int

    f = func(x int, y int) int { return x + y + 1 }

    fmt.Printf("%d", f(1, 2))

    // We compare the above defined function plus with the
    // locally defined function f.
    // Which is of the following statements holds?
    // A: plus and f are identical.
    // B: plus and f are of the same type.
    // C: plus and f are of different type.
}

func add(x int) func(int) int {
    return func(y int) int { return x + y }
}

func q5() {
    var f func(int) func(int) int

    var g func(int) func(int) int

    f = add
    g = add

    fmt.Printf("%d", f(1)(2))
    fmt.Printf("%d", (g(1))(2))

    // We compare the above defined functions f and g.
    // Which of the following statements holds?
    // A: f and g are identical.
    // B: f and g are of different type.
    // C: f and g are of the same type but need to be called differently.

}

func q6() {

    f := add(1)
    fmt.Printf("%d", f(2))

    // What is the type of f?
    // A: f has no type.
    // B: f has type func(int) int
    // C: f has type func(int) func(int) int
}

func q7() {
    g := func(x int) func(int) int {
        return func(y int) int { return x + y }
    }
    fmt.Printf("%d", g(1)(2))

    // What is the type of g?
    // A: g has type func(int) func(int) int
    // B: g has type int
    // C: g has type func(int) int

}

func q8() {

    curry := func(f func(int, int) int) func(int) func(int) int {
        return func(x int) func(int) int {
            return func(y int) int {
                return f(x, y)
            }
        }

    }

    fmt.Printf("%d", curry(plus)(1)(2))

    // via the curry function, add can be expressed in terms of plus. How?
    // A: add := plus(curry)
    // B: add := curry(plus)
    // C: This is impossible.

}

func q9() {

    uncurry := func(g func(int) func(int) int) func(int, int) int {
        return func(x int, y int) int {
            return (g(x))(y)
        }
    }

    fmt.Printf("%d", uncurry(add)(1, 2))

    // via the uncurry function, plus can be expressed in terms of add. How?
    // A: plus := uncurry(add)
    // B: plus := add(uncurry)
    // C: This is impossible.

}

func main() {
    q1()
    fmt.Printf("Hi")

}

// Solutions

// q2:C

// q3:B

// q4:B

// q5:A

// q6:B

// q7:A

// q8:B

// q9:A

Methods and Interfaces

package main

import "fmt"

// Quiz.
// Test your Go knowledge.
// You are given some program text and have to answer questions
// by selecting the right answer.
// Solutions can be found below.

// Methods and interfaces

type Int struct{ val int }

func plus(x int, y int) int {
    return x + y
}

func (i Int) plus(x int) int {
    return i.val + x
}

func m1() {
    x := plus(1, 2) // P1

    y := Int{1}

    x = y.plus(2) // P2

    fmt.Printf("%d", x)

}

/*

At location P1 we find a functional call.
At location P2 we find a method call.

 What is result of calling y.plus(2)?
 A: There's no result.
 B: Same result as for plus(1,2).
 C: Different result compared to plus(1,2).

*/

// m2

// Consider again

/*

func (i Int) plus(x int) int {
    return i.val + x
}


*/

/*

What is the argument/object called on which the plus method is called?

 A: Sender
 B: Caller
 C: Receiver

*/

// m3

// Consider

/*

func (i Int) plus(x int) int {
    return i.val + x
}

func (i Int) plus(x Int) int {
   return i.val + x.val

}

*/

/*

The above definitions are not allowed. Why?
 A: The val element in i does not exist.
 B: Method dispatch is based on the receiver type.
    For each method there can be at most one definition for a receiver (type).
    There exists already a definition for the receiver type Int.
 C: There's no problem. This is allowed.


*/

// m4

// Consider

type A interface {
    f1() int
}

type B interface {
    A
    f2(int) int
}

type INT struct{ val int }

func (s INT) f1() int {
    return s.val
}

func g(x B, y int) int {
    return x.f2(y)
}

func m4() {
    var x INT = INT{1}

    y := g(x, 3) // P

    fmt.Printf("%d", x.val)
    fmt.Printf("%d", y)

}

/*

The program text marked P yields a type error. Why?
 A: The type of y is undefined.
 B: g expects an additional argument.
 C: x only supports f1 but not f2 but f2 is required by interface B.

 Hint: You can just copy and run the code to get the answer.


*/

// m5

// Additionally we consider

type C interface {
    f2(int) int
    f1() int
}

func (s INT) f2(x int) int {
    return s.val + x
}

func m5() {
    var x1 B
    var x2 C

    y := INT{1}

    x1 = y

    x2 = x1

    z := g(x2, 1)
    fmt.Printf("%d", z)
}

// Observe the following.
// 1. y is of type INT.
// 2. y can be assigned to x1 (of type B) because
//    the type INT supports interface B.
// 3. x2 can be assigned to x1 because
//    interfaces B and C are structurally equivalent (same set of methods).
// 4. Hence, the above type checks and can be executed.

// Is the above true or not?
// A: True
// B: Not true.

func main() {

    fmt.Printf("")
}

// Solutions

// m1:B

// m2:C

// m3:B

// m4:C

// m5:A