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

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?

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.

Related

Converting private, dynamic type from interface{}

I'm trying to test around an SQL query wherein one of the arguments is a gosnowflake.Array (essentially a wrapper to a slice) using the go-sqlmock package. Normally, something like this requires me to create a value converter, which I have included:
func (opt arrayConverterOption[T]) ConvertValue(v any) (driver.Value, error) {
casted, ok := v.(*[]T)
if ok {
Expect(*casted).Should(HaveLen(len(opt.Expected)))
for i, c := range *casted {
Expect(c).Should(Equal(opt.Expected[i]))
}
} else {
fmt.Printf("Type: %T\n", v)
return v, nil
}
return "TEST_RESULT", nil
}
Now, this function is called for every argument submitted to the query. I use it to test the correctness of the values in the slice or pass the argument through if it isn't one. The problem I'm having is that, when I create a arrayConverterOption[string] and give it a gosnowflake.Array(["A", "B", "C"]) as an argument, the type assertion fails because gosnowflake.Array returns an internal dynamic type, *stringArray, which is defined as a *[]string.
So you can see my dilemma here. On the one hand, I can't convert v because it's an interface{} and I can't alias v because the inner type is not *[]string, but *stringArray. So then, what should I do here?
I didn't find a way to do this without resulting to reflection. However, with reflction I did manage it:
var casted []T
var ok bool
value := reflect.ValueOf(v)
if value.Kind() == reflect.Pointer {
if inner := value.Elem(); inner.Kind() == reflect.Slice {
r := inner.Convert(reflect.TypeOf([]T{})).Interface()
casted, ok = r.([]T)
}
}
So, this code checks specifically for anything that is a pointer to a slice, which my dynamic type is. Then it uses reflection to convert the inner object to the slice type I was expecting. After that, I call Interface() on the result to get the interface{} from the reflected value and then cast it to a []T. This succeeds. If it doesn't then I'm not working with one of those dynamically typed slices and I can handle the type normally.

Interfaces can be of type nil but that doesn't mean they are nil?

I wrote a bit of code that in effect does this:
package main
import "fmt"
type SomeInterface interface {
Retrieve(identifier string)
}
type SomeStruct struct {}
func (r SomeStruct) Retrieve(identifier string) {
fmt.Println("identifier ", identifier)
}
type Handler struct {
Name string
SomeObject SomeInterface
}
func main() {
var someStruct *SomeStruct
var h = Handler{
Name: "helo",
SomeObject: someStruct,
}
fmt.Printf("before %+v\r\n", h.SomeObject)
if h.SomeObject == nil {
fmt.Printf("during %+v\r\n", h.SomeObject)
}
fmt.Printf("after %+v\r\n", h.SomeObject)
}
Please can someone explain to me why the output of the above is:
before <nil>
after <nil>
I've been reading about interfaces of type nil but in this case I have assigned the interface to a pointer that hasn't been assigned so I would have thought that the interface == nil and I would see during <nil> - alas it is not the case.
An interface value is a simple data structure with two parts, a type and an underlying value. So, the interface value itself can be nil, or the interface value can exist but the underlying value can be nil. For example:
var x interface{} = nil // x is nil
var y interface{} = (interface{})(nil) // y is a interface{}, which *contains* nil
This is in some ways conceptually similar to this difference:
var x []*int = nil // x is nil
var y []*int = []*int{nil} // y is a []*int, which *contains* nil
fmt.Printf obscures the difference in the case of an interface because of the way it formats the output; you could see the difference more clearly using reflection if you wanted to.
SomeObject is not nil, it just points to SomeStruct which is nil.
i think the confusion is fmt.Printf prints <nil> for this case cuz it's following the pointer and that end result is nil.
In Go, a variable referring to an implementer of some interface can have many types. It can be of type <nil> (yes, nil can describe a type as well as a value), it can be the type of one of its implementers, or it can be the type of a pointer to one of its implementers. By default, a variable referring to an interface is of type nil. Once you've assigned something to it (other than nil itself), it will then take on the type of the thing you've assigned to it (again, either the type of one of its implementers, or a pointer to one of those types).
You can print the type of an interface variable with %T, and its value with %v:
func main() {
var i SomeInterface
fmt.Printf("%T, %v\n", i, i) // Prints <nil>, <nil>
var someStruct SomeStruct
i = someStruct
fmt.Printf("%T, %v\n", i, i) // Prints main.SomeStruct, {}
var someStructPtr *SomeStruct
i = someStructPtr
fmt.Printf("%T, %v\n", i, i) // Prints *main.SomeStruct, <nil>
}
Now, whenever you compare h.SomeObject == nil, the comparison will only be evaluated as true if both the types and values of the two operands match. In your case, the value of h.SomeObject is clearly <nil> (after all, the value of someStruct is surely <nil>, and you store its value in h.SomeObject). The type of h.SomeObject, based on what I just explaind, must be *SomeStruct. The value of nil is obviously <nil>.
However, what is the type of nil?
Well, nil can take on many types, and the compiler has to decide what type it should take on for each usage. When it comes to comparisons and assignments, it simply takes on the type of the thing it is being compared to or assigned to. For instance, if you are comparing an integer pointer to nil, then the nil in such a case will be of type *int.
But all of this has to be decided at compile time, and a variable referring to an interface can change types during runtime. So when you compare a variable referring to an interface to nil, what type does the compiler give to the nil operand in such a case? Well, it gives it the only sensible type, <nil>.
For a final example, consider the following code:
func main() {
var p *SomeStruct = nil // = nil is optional; pointers default to nil
var i SomeInterface = p
printf("%t\n", p == nil) // Prints true
printf("%t\n", p == i) // Prints true
printf("%t\n", i == nil) // Prints false
}
p == nil is true, since p is of type *SomeStruct with value <nil>, and nil (in this case) is also of type *SomeStruct with value <nil>.
p == i is true, since i is also of type *SomeStruct with value <nil> (it is simply storing the type and value of p).
However, i == nil is false, because nil, in this case, takes on the type <nil> rather than *SomeStruct.
The solution around this problem is simply to never store something of value <nil> in an interface-referring variable, except for nil itself. That way, whenever the value of the interface-referring variable is <nil>, its type will also be <nil>, and comparisons against nil will work as expected. For this reason, you often see code that looks like this:
if p == nil {
i = nil
} else {
i = p
}

how to append nil to dynamic type slice by reflect.Append

Code below will raise a runtime error when append reflect.Value of nil:
package main
import (
"fmt"
"reflect"
)
func main() {
var list []interface{}
v := reflect.ValueOf(list)
v = reflect.Append(v, reflect.ValueOf(1)) // [1]
v = reflect.Append(v, reflect.ValueOf("1")) // [1, 1]
v = reflect.Append(v, reflect.ValueOf(nil)) // runtime error
fmt.Println(v)
}
So
why there is a runtime error?
how can I use reflect.Append to add a nil to interface{} slice?
interface{} is an interface type, and they are "tricky". They are wrappers around a concrete value and the concrete type, schematically a (value, type) pair.
So when you pass a concrete value to a function that expects an interface{} value, the concrete value will be wrapped in an interface{} value automatically, implicitly. If you pass a nil to such a function, the interface value itself will be nil. If you pass a nil pointer to it, such as (*int)(nil), the interface value will not be nil but an interface value holding "(nil, *int)".
If you pass nil to reflect.ValueOf(), it results in a "zero" reflect.Value which represents no value at all. If you pass this to reflect.Append(), it will not have the type information, it will not know what you want to append to the slice.
It is possible to create a value that represents the nil interface value.
To do that, we may start from the type descriptor of a value of an interface pointer (pointers to interface rarely makes sense, but this is one of them). We navigate to the type descriptor of the pointed type, which is interface{}. We obtain a zero value of this type (using reflect.Zero()), which is nil (zero value of interface types is nil).
Zero returns a Value representing the zero value for the specified type. The result is different from the zero value of the Value struct, which represents no value at all.
So this is how it looks like:
typeOfEmptyIface := reflect.TypeOf((*interface{})(nil)).Elem()
valueOfZeroEmptyIface := reflect.Zero(typeOfEmptyIface)
v = reflect.Append(v, valueOfZeroEmptyIface)
Or as a single line:
v = reflect.Append(v, reflect.Zero(reflect.TypeOf((*interface{})(nil)).Elem()))
To check the results, let's use:
fmt.Printf("%#v\n", v)
And also let's type-assert back the slice, and add a nil value using the builtin append() function:
list = v.Interface().([]interface{})
list = append(list, nil)
fmt.Printf("%#v\n", list)
Let's do an explicit, extra check if the elements are nil (compare them to nil). Although using %#v verb this is redundant, %v likes to print non-nil interfaces holding nil concrete values just as nil (the same as if the interface value itself would be nil).
fmt.Println(list[2] == nil, list[3] == nil)
Ouptut will be (try it on the Go Playground):
[]interface {}{1, "1", interface {}(nil)}
[]interface {}{1, "1", interface {}(nil), interface {}(nil)}
true true
See related question: Hiding nil values, understanding why golang fails here
Also: The Go Blog: The Laws of Reflection

This nil instance of a struct, that satisfies the error interface, is not showing as nil

This should be a gimme for someone. Why do I not get what I expect ("Error is not nil") here?
http://play.golang.org/p/s8CWQxobVL
type Goof struct {}
func (goof *Goof) Error() string {
return fmt.Sprintf("I'm a goof")
}
func TestError(err error) {
if err == nil {
fmt.Println("Error is nil")
} else {
fmt.Println("Error is not nil")
}
}
func main() {
var g *Goof // nil
TestError(g) // expect "Error is nil"
}
This is, it turns out, a Frequently Asked Question about Go, and the short answer is that interface comparisons compare the type and the value, and (*Goof)(nil) and error(nil) have different types.
Since if err != nil is standard, you want a return value that'll work with it. You could declare var err error instead of var g *Goof: err's zero value is conveniently error(nil)
Or, if your func returns an error, return nil will return what you want.
For more background, here's the start of the FAQ's answer:
Under the covers, interfaces are implemented as two elements, a type and a value. The value, called the interface's dynamic value, is an arbitrary concrete value and the type is that of the value. For the int value 3, an interface value contains, schematically, (int, 3).
An interface value is nil only if the inner value and type are both unset, (nil, nil). In particular, a nil interface will always hold a nil type. If we store a pointer of type *int inside an interface value, the inner type will be *int regardless of the value of the pointer: (*int, nil). Such an interface value will therefore be non-nil even when the pointer inside is nil.
And == is strictly checking if the types are identical, not if a type (*Goof) implements an interface (error). Check out the original for more.
If it helps clarify, this doesn't only happen with nil: in this example, the data underlying the x and y variables is obviously 3, but they have different types. When you put x and y into interface{}s, they compare as unequal:
package main
import "fmt"
type Bob int
func main() {
var x int = 3
var y Bob = 3
var ix, iy interface{} = x, y
fmt.Println(ix == iy)
}

Can't return nil, but zero value of slice

I am having the case in which a function with the following code:
func halfMatch(text1, text2 string) []string {
...
if (condition) {
return nil // That's the final code path)
}
...
}
is returning []string(nil) instead of nil. At first, I thought that perhaps returning nil in a function with a particular return type would just return an instance of a zero-value for that type. But then I tried a simple test and that is not the case.
Does anybody know why would nil return an empty string slice?
Nil is not a type. It is a description of the zero value for maps, chans, pointers, functions, slices, and interfaces.
When you put "nil" in your program, go gives it a type depending on the context. For the most part, you never need to explicitly type your nil. This is no exception, the compiler knows it must be a []string(nil) because the type returned is []string.
A nil string slice is a slice with no backing array and a length/capacity of zero. You may compare it to the literal "nil" and can get its length and capacity. It is a []string, just empty. If you wish to have an empty []string that is not nil, return []string{}. This creates a backing array (of length zero) and makes it no longer equivalent to nil.
I believe I know what's going on. The assert library I am using (github.com/bmizerany/assert) is using internally a reflect.DeepEqual.
The return value of func halfMatch(text1, text2 string) []string is always of type []string, but if it returns nil and is compared to a nil value via the == operator, it will return true. However, if reflect.DeepEqual is used, the type will matter and it won't consider both values the same.
playgound link with the test
I think maybe you are being confused by the output of print. (playground link)
package main
import "fmt"
func f() []string {
return nil // That's the final code path)
}
func main() {
result := f()
fmt.Printf("result = %v\n", result)
fmt.Printf("result = %v\n", result == nil)
}
Which produces
result = []
result = true
So I think the output really is nil
Go will return an enpty slice if condition is true.
There is a problem with your "test" because if you try to compare [] with nil, you get true.
I have modified your test to show you what I mean
package main
import "fmt"
func main() {
//fmt.Println(test1("") == nil)
fmt.Println(test1("")) // prints []
}
func test1(text1 string) []string {
if len(text1) > 0 {
return []string{text1}
}
return nil
}

Resources