Katkat

Predict the Output of a Go Program That Appends to a Sub-Slice

ZooxSoftware Engineer · Onsite

Last updated

A Go output-prediction question: a short program takes a sub-slice of a slice, appends to it inside a helper function and prints three slices. It tests how slice headers, length, capacity and shared backing arrays interact with append, and whether a candidate can trace them precisely.

Without running it, predict exactly what this Go program prints, and explain why each of the three lines comes out the way it does.

package main

import "fmt"

func foo(a []int) []int {
	a = append(a, len(a))
	return a
}

func main() {
	x := []int{1, 2, 3, 0, 0, 0, 0}
	y := x[:3]
	z := foo(y)
	fmt.Println(x)
	fmt.Println(y)
	fmt.Println(z)
}

This was an output-prediction exercise: no conceptual questions up front, just the code and a request for its output.

Clarifying Questions

  • Do you want only the three printed lines, or also the length and capacity of every slice after each statement?
  • May I assume the standard formatting of fmt.Println for an []int: values separated by spaces inside square brackets?

Hints

Hint 1

Track every slice: For `x`, `y`, the parameter `a` and `z`, write down the length, the capacity and the backing array each one refers to.

Hint 2

What append does with room to spare: Decide whether the `append` inside `foo` has to allocate, and what that means for memory that `x` can also see.

Follow-up questions

  • What does the program print if `x` is declared as `[]int{1, 2, 3}` instead?
  • What changes if `main` uses the full slice expression `y := x[:3:3]`?
  • After `z := foo(y)`, the program also runs `w := append(y, 99)`. What do `z` and `x` print now, and why is this pattern a bug in real code?
  • How would you change `foo` so that it can never modify a caller's data?