News for hackers. Stuff that matters.
Re:Go says Wat by jrockway on Friday September 07, 2018 @06:01PM (#17937991)
The slices are actually confusing and I've written quite a few test programs to teach myself the WATs because the behavior is not obvious from the syntax. Remember, slices are very mutable, regardless of the lack of a * in the function parameter. This works as you'd expect:

    type thing struct {
	    foo int
    }

    func f(x thing) {
	    x.foo = 42
    }

    func main() {
	    var x thing
	    x.foo = 1234
	    fmt.Printf("x before: %v\n", x)
	    f(x)
	    fmt.Printf("x after: %v\n", x)
    }
This prints 1234 and 1234 as you'd expect. That's pass by value in action. But what if we mutate a slice?

    func f(x []int) {
	    x[1] = 42
    }

    func main() {
	    x := []int{1, 2, 3}
	    fmt.Printf("x before: %v\n", x)
	    f(x)
	    fmt.Printf("x after: %v\n", x)
    }
Of course, this prints [1 2 3] and [1 42 3]. While you're passing the slice by value, the backing array is not copied.

As you write more go, you will begin to fully see the existence of a backing array. Try this program:

    func main() {
	    x := []int{1,2,3,4}
	    y := x[1:2]
	    y[0] = 42
	    fmt.Printf("x: %v, y: %v\n", x, y)
    }
You know that [:] does no copying (there is a copy() function that copies stuff) and just shares the same backing array between each slice, so you aren't surprised when this prints "x: [1 42 3 4], y: [42]".

Now, add some knowledge from the documentation about how append() works. You use the idiom slice = append(slice, element) because the documentation says, sometimes the slice is updated in place when there is enough capacity for that to occur, and sometimes the slice is copied to a new slice and returned.

This then leads to your "WAT" in WAT 2. Because you _know_ that the data you appended is actually in the backing array, but for some reason Go isn't showing it to you.

You can see this in action with a very poor example I just wrote:

    func main() {
	    x := []int{1, 2, 3, 4, 5, 6}
 	    y := x[0:0]
	    fmt.Printf("x: %v, y: %v\n", x, y)
	    fmt.Printf("intermediate result that's not saved: %v\n", append(y, 9, 8, 7, 6, 5))
	    fmt.Printf("x: %v, y: %v\n", x, y)
    }
After all of this, x is [9 8 7 6 5 6]. So you _know_ that append is more than happy to mess with your backing array. You just need a slice with the right length to be able to see all the data in there.

For that reason, I think WAT 2 is worthwhile. Most people know _just enough_ about slices to be dangerous, and so are surprised when there is an additional complication that they haven't thought about.

Re:Go says Wat by randomdata on Friday September 07, 2018 @11:36PM (#17939256)
> This prints 1234 and 1234 as you'd expect.

Until it doesn't.

  type thing struct {
  	foo *int
  }

  func f(x thing) {
  	*x.foo = 42
  }

  func main() {
  	v := 1234
  	var x thing
  	x.foo = &v
  	fmt.Printf("x.foo before: %v\n", *x.foo)
  	f(x)
  	fmt.Printf("x.foo after: %v\n", *x.foo)
  }
Or maybe that is what you'd expect, but then slices shouldn't seem so mysterious.