How to make a function with inferred nillable comparable generics? - go

Consider the following function:
func NilCompare[T comparable](a *T, b *T) bool {
if a == nil && b == nil {
// if both nil, we consider them equal
return true
}
if a == nil || b == nil {
// if either is nil, then they are clearly not equal
return false
}
return *a == *b
}
This function works. However, when I call it, I must supply the type, as Go cannot infer (cannot infer T) it, e.g. NilCompare[string](a, b), where a and b are *string.
If I modify T to be *comparable and a and b to be T, I get this error instead:
cannot use type comparable outside a type constraint: interface is (or embeds) comparable
I am using Go 1.19.2.
$ go version
go version go1.19.2 linux/amd64
Ironically, my IDE (GoLand 2022.2.3) believes that the above function should be inferrable.
Is there a way to make a function that take nillable comparable and make it inferrable? Or am I doing it correct, but I need to help the go function along?

Type inference just works, in this case. You simply can't infer T using literal nil, as NilCompare(nil, nil) because that doesn't really carry type information.
To test your function with nils do this:
package main
import "fmt"
func main() {
var a *string = nil
var b *string = nil
// a and b are explicitly typed
res := NilCompare(a, b) // T inferred
fmt.Println(res) // true
}
this also would work:
func main() {
// literal nil converted to *string
res := NilCompare((*string)(nil), (*string)(nil)) // T inferred
fmt.Println(res) // true
}

Related

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
}

Can I compare variable types with .(type) in Golang?

I'm quite confused about the .(type) syntax for interface variables. Is it possible to use it like this:
var a,b interface{}
// some code
if first.(type) == second.(type) {
}
or is reflect.TypeOf() the only option to check if the underlying types of a and b are the same type? What comparison am I making in the code above?
someInterface.(type) is only used in type switches. In fact if you tried to run that you'd see that in the error message.
func main() {
var a, b interface{}
a = 1
b = 1
fmt.Println(a.(type) == b.(type))
}
prog.go:10: use of .(type) outside type switch
What you could do instead is a.(int) == b.(int), which is really no different from int(a) == int(b)
func main() {
var a, b interface{}
a = 1
b = 1
fmt.Println(a.(int) == b.(int))
}
true
func isType(a, b interface{}) bool {
return fmt.Sprintf("%T", a) == fmt.Sprintf("%T", b)
}
The "%T" fmt option uses reflection under the hood, which would make the above statement practically that same as:
func isType(a, b interface{}) bool {
return reflect.TypeOf(a) == reflect.TypeOf(b)
}
Either one would work, and won't cause a panic trying to utilize any kind of type assertion like some of the other suggestions.
You'd need to specify the type. That syntax is used to make type assertions about interfaces, not about checking the specific type.
You'll have to use reflect.TypeOf for that.
You can view this answer for a proper use of type assertions.
Please try this:
for key, value := range data {
switch v := value.(type) {
case string:
fmt.Println(key, value, "(string)")
case float64:
fmt.Println(key, value, "(float64)")
case []interface{}:
fmt.Println(key, value, "(interface)")
}
}
...
and you can use for all types in any interface...

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

How to check variable type at runtime in Go language

I have few C functions declared like this
CURLcode curl_wrapper_easy_setopt_long(CURL* curl, CURLoption option, long param);
CURLcode curl_wrapper_easy_setopt_str(CURL* curl, CURLoption option, char* param);
I would like to expose those as one Go function like this
func (e *Easy)SetOption(option Option, param interface{})
so I need to be able to check param type at runtime. How do I do that and is this good idea (if not what is good practice in this case)?
It seems that Go have special form of switch dedicate to this (it is called type switch):
func (e *Easy)SetOption(option Option, param interface{}) {
switch v := param.(type) {
default:
fmt.Printf("unexpected type %T", v)
case uint64:
e.code = Code(C.curl_wrapper_easy_setopt_long(e.curl, C.CURLoption(option), C.long(v)))
case string:
e.code = Code(C.curl_wrapper_easy_setopt_str(e.curl, C.CURLoption(option), C.CString(v)))
}
}
The answer by #Darius is the most idiomatic (and probably more performant) method. One limitation is that the type you are checking has to be of type interface{}. If you use a concrete type it will fail.
An alternative way to determine the type of something at run-time, including concrete types, is to use the Go reflect package. Chaining TypeOf(x).Kind() together you can get a reflect.Kind value which is a uint type: http://golang.org/pkg/reflect/#Kind
You can then do checks for types outside of a switch block, like so:
import (
"fmt"
"reflect"
)
// ....
x := 42
y := float32(43.3)
z := "hello"
xt := reflect.TypeOf(x).Kind()
yt := reflect.TypeOf(y).Kind()
zt := reflect.TypeOf(z).Kind()
fmt.Printf("%T: %s\n", xt, xt)
fmt.Printf("%T: %s\n", yt, yt)
fmt.Printf("%T: %s\n", zt, zt)
if xt == reflect.Int {
println(">> x is int")
}
if yt == reflect.Float32 {
println(">> y is float32")
}
if zt == reflect.String {
println(">> z is string")
}
Which prints outs:
reflect.Kind: int
reflect.Kind: float32
reflect.Kind: string
>> x is int
>> y is float32
>> z is string
Again, this is probably not the preferred way to do it, but it's good to know alternative options.
quux00's answer only tells about comparing basic types.
If you need to compare types you defined, you shouldn't use reflect.TypeOf(xxx). Instead, use reflect.TypeOf(xxx).Kind().
There are two categories of types:
direct types (the types you defined directly)
basic types (int, float64, struct, ...)
Here is a full example:
type MyFloat float64
type Vertex struct {
X, Y float64
}
type EmptyInterface interface {}
type Abser interface {
Abs() float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func (f MyFloat) Abs() float64 {
return math.Abs(float64(f))
}
var ia, ib Abser
ia = Vertex{1, 2}
ib = MyFloat(1)
fmt.Println(reflect.TypeOf(ia))
fmt.Println(reflect.TypeOf(ia).Kind())
fmt.Println(reflect.TypeOf(ib))
fmt.Println(reflect.TypeOf(ib).Kind())
if reflect.TypeOf(ia) != reflect.TypeOf(ib) {
fmt.Println("Not equal typeOf")
}
if reflect.TypeOf(ia).Kind() != reflect.TypeOf(ib).Kind() {
fmt.Println("Not equal kind")
}
ib = Vertex{3, 4}
if reflect.TypeOf(ia) == reflect.TypeOf(ib) {
fmt.Println("Equal typeOf")
}
if reflect.TypeOf(ia).Kind() == reflect.TypeOf(ib).Kind() {
fmt.Println("Equal kind")
}
The output would be:
main.Vertex
struct
main.MyFloat
float64
Not equal typeOf
Not equal kind
Equal typeOf
Equal kind
As you can see, reflect.TypeOf(xxx) returns the direct types which you might want to use, while reflect.TypeOf(xxx).Kind() returns the basic types.
Here's the conclusion. If you need to compare with basic types, use reflect.TypeOf(xxx).Kind(); and if you need to compare with self-defined types, use reflect.TypeOf(xxx).
if reflect.TypeOf(ia) == reflect.TypeOf(Vertex{}) {
fmt.Println("self-defined")
} else if reflect.TypeOf(ia).Kind() == reflect.Float64 {
fmt.Println("basic types")
}
See type assertions here:
http://golang.org/ref/spec#Type_assertions
I'd assert a sensible type (string, uint64) etc only and keep it as loose as possible, performing a conversion to the native type last.
func (e *Easy)SetOption(option Option, param interface{}) {
if s, ok := param.(string); ok {
// s is string here
}
// else...
}
What's wrong with
func (e *Easy)SetStringOption(option Option, param string)
func (e *Easy)SetLongOption(option Option, param long)
and so on?

Resources