-1

I'm a newbie Go programmer confused by the below behaviour. I expected the program to fail at t2 with error

first argument to append must be a slice; have untyped nil

but Go is happy when passing in nil as first parameter to append when it's a parameter to a method?

package main

import "fmt"

type Thing struct {
    data []string
}

func NewThing(extra []string) Thing {
    return Thing{
        data: append(extra, "b"),
    }
}

func main() {
    t := NewThing([]string{"a"})
    fmt.Println(t.data) // [a b]

    t2 := NewThing(nil)
    fmt.Println(t2.data) // [b]

    //_ = Thing{ // build failed: first argument to append must be a slice; have untyped nil
    //  data: append(nil, "b"),
    //}
}

Playground: https://go.dev/play/p/Cxi7fRHu3Wi

Is this just a convenience feature or am I understanding this wrong?

blackgreen
  • 34,072
  • 23
  • 111
  • 129
Tessa
  • 127
  • 1
  • 7
  • 2
    [This issue](https://github.com/golang/go/issues/1295) discusses a proposal to make `append(nil, slice)` valid (dates back to 2010 but may provide some extra context). – Brits Jun 18 '22 at 02:42
  • Related: [Hiding nil values, understanding why Go fails here](https://stackoverflow.com/questions/29138591/hiding-nil-values-understanding-why-go-fails-here) – blackgreen Jun 18 '22 at 07:01

1 Answers1

2

It is a convenience that the capacity and length of a nil slice is zero. From there, append works as normal when passed a nil slice.

The call append(nil, "b") does not compile because nil has no type. The compiler cannot determine the type of the result because the slice argument does not have a type.

The call append(extra, "b") works when extra is nil because extra is a typed value (a []string). Given the slice type, the compiler knows that the result is []string and that the appended elements must be assignable to string.

The call append([]string(nil), "b") also works because the expression []string(nil) is a typed value.