Martin Sulzmann
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
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