Can't return nil, but zero value of slice - go

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
}

Related

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

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.

Return default value for generic type

How do you return nil for a generic type T?
func (list *mylist[T]) pop() T {
if list.first != nil {
data := list.first.data
list.first = list.first.next
return data
}
return nil
}
func (list *mylist[T]) getfirst() T {
if list.first != nil {
return list.first.data
}
return nil
}
I get the following compilation error:
cannot use nil as T value in return statement
You can't return nil for any type. If int is used as the type argument for T for example, returning nil makes no sense. nil is also not a valid value for structs.
What you may do–and what makes sense–is return the zero value for the type argument used for T. For example the zero value is nil for pointers, slices, it's the empty string for string and 0 for integer and floating point numbers.
How to return the zero value? Simply declare a variable of type T, and return it:
func getZero[T any]() T {
var result T
return result
}
Testing it:
i := getZero[int]()
fmt.Printf("%T %v\n", i, i)
s := getZero[string]()
fmt.Printf("%T %q\n", s, s)
p := getZero[image.Point]()
fmt.Printf("%T %v\n", p, p)
f := getZero[*float64]()
fmt.Printf("%T %v\n", f, f)
Which outputs (try it on the Go Playground):
int 0
string ""
image.Point (0,0)
*float64 <nil>
The *new(T) idiom
This has been suggested as the preferred option in golang-nuts. It is probably less readable but easier to find and replace if/when some zero-value builtin gets added to the language.
It also allows one-line assignments.
The new built-in allocates storage for a variable of any type and returns a pointer to it, so dereferencing *new(T) effectively yields the zero value for T. You can use a type parameter as the argument:
func Zero[T any]() T {
return *new(T)
}
In case T is comparable, this comes in handy to check if some variable is a zero value:
func IsZero[T comparable](v T) bool {
return v == *new(T)
}
var of type T
Straightforward and easier to read, though it always requires one line more:
func Zero[T any]() T {
var zero T
return zero
}
Named return types
If you don't want to explicitly declare a variable you can use named returns. Not everyone is fond of this syntax, though this might come in handy when your function body is more complex than this contrived example, or if you need to manipulate the value in a defer statement:
func Zero[T any]() (ret T) {
return
}
func main() {
fmt.Println(Zero[int]()) // 0
fmt.Println(Zero[map[string]int]()) // map[]
fmt.Println(Zero[chan chan uint64]()) // <nil>
}
It's not a chance that the syntax for named returns closely resembles that of var declarations.
Using your example:
func (list *mylist[T]) pop() (data T) {
if list.first != nil {
data = list.first.data
list.first = list.first.next
}
return
}
Return nil for non-nillable types
If you actually want to do this, as stated in your question, you can return *T explicitly.
This can be done when the type param T is constrained to something that excludes pointer types. In that case, you can declare the return type as *T and now you can return nil, which is the zero value of pointer types.
// constraint includes only non-pointer types
func getNilFor[T constraints.Integer]() *T {
return nil
}
func main() {
fmt.Println(reflect.TypeOf(getNilFor[int]())) // *int
fmt.Println(reflect.TypeOf(getNilFor[uint64]())) // *uint64
}
Let me state this again: this works best when T is NOT constrained to anything that admits pointer types, otherwise what you get is a pointer-to-pointer type:
// pay attention to this
func zero[T any]() *T {
return nil
}
func main() {
fmt.Println(reflect.TypeOf(zero[int]())) // *int, good
fmt.Println(reflect.TypeOf(zero[*int]())) // **int, maybe not what you want...
}
You can init a empty variable.
if l == 0 {
var empty T
return empty, errors.New("empty Stack")
}

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
}

Type assertion when returning an interface

I'm new to golang; however based on my current knowledge I understand that a value-type and a reference-type can both fulfill an interface. But it seems in regards to type assertion, how you return a struct does matter. See the following:
package main
import (
"fmt"
)
type SomeError interface {
Error() string
}
type ConcreteError struct{}
func (ConcreteError) Error() string {
return "?"
}
func returnPointer() SomeError {
return &ConcreteError{}
}
func returnVal() SomeError {
return ConcreteError{}
}
func main() {
pointer := returnPointer()
value := returnVal()
_, pointerWithPointer := pointer.(*ConcreteError);
_, pointerWithValue := pointer.(ConcreteError);
_, valueWithValue := value.(ConcreteError);
_, valueWithPointer := value.(*ConcreteError)
fmt.Printf("Returning a pointer, assert using (*ConcreteError): %v\n", pointerWithPointer); // true
fmt.Printf("Returning a pointer, assert using (ConcreteError): %v\n", pointerWithValue); // false
fmt.Printf("Returning a value, assert using (ConcreteError): %v\n", valueWithValue); // true
fmt.Printf("Returning a value, assert using (*ConcreteError): %v\n", valueWithPointer); // false
}
So if my understanding is correct, the user needs to know how the struct is returned to correctly assert its type?
I'm going to guess and assume the standard practice in golang is to always return a pointer to a struct(i.e like *PathError)?
link to play: here
So if my understanding is correct, the user needs to know how the struct is returned to correctly assert its type?
It depends. If you need the type assertion to pass - you surely need to know the exact type of the value. a and *a are different types.
I'm going to guess and assume the standard practice in golang is to always return a pointer to a struct(i.e like *PathError)?
No.

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)
}

Resources