This piece of code looks quite counter-intuitive to me:
var first *byte
var second interface{}
fmt.Println(first, first == nil) // <nil> true
fmt.Println(second, second == nil) // <nil> true
fmt.Println(first == second) // false
As far as I understand, the case is that the first variable is a pointer to an empty variable of type byte, whereas the second is an empty interface. So, as the variables are not the same type, they are not considered equal.
But if they are not equal to each other, how can they be equal to some third value? Is it common situation in programming languages when Transitive Law is not held?
The identifier nil represents the zero value for channel, pointer, interface, function, map and slice types.
The zero value for a *byte is not equal to the zero value for an interface{}.
Nil does represent a zero value, but each value in go also has a type.
I have also seen something similar to this in testing when methods return a custom error type as err, and then check to see if the errors are equal which fails because Go intrinsically believes they are different because you have not type asserted it to the custom error type.
Here's a more interesting example of intransitivity of Go's == operator. It doesn't rely on nil; for types like functions and maps, x==nil is best thought of as an special operator, since values of those types aren't comparable to each other.
// "hello" != x == s == "hello"
func main() {
type S string
var s S = "hello"
var x interface{} = s
fmt.Println(s == "hello") // s == "hello"
fmt.Println(x == s) // x == s
fmt.Println(x == "hello") // x != "hello"
}
One way to explain this anomaly is that there are really two different equality operators at work here. The first comparison has type S, but the second and third have type interface{}. Once the types are erased, the interface conversions become explicit and each "==" is replaced by the appropriate comparison operator for its type. Those comparison operators, individually, are true equivalence relations, which is to say they are transitive.
Related
I recently read on a popular programming forum that Go supports a handful of "typelesss" values — notably, nil, Go's null value/bottom type. I have fairly limited experience with Go, and one of the statements made on this forum caught me off guard — namely, that it's illegal to write x := nil in Go.
Sure enough, a toy Go program with that line doesn't compile and the compiler error clearly points out that the comment from the forum checks out: declaration and assignment of a variable to nil is disallowed. This seems like a bit of an odd limitation, but things get stranger.
It's a common idiom in Go to return partial errors by returning a tuple from a function. Something like this:
func might_error() (int, error) {
return 1, nil
}
func main() int {
x, err := might_error()
if err != nil {
panic("err was not nil!")
}
return x
}
This has at least two inconsistencies as far as I can tell:
First, even though nil is typeless on paper, it takes on the error type (by way of it implementing the Error interface combined with Go's duck typing) for the purposes of conforming to might_error's return type signature.
Second, it seems like nil is being used for that previously-illegal declaraiton-and-assignment in main, and in a situation where (at least in comparable languages) might_error could be treated as a constexpr.
Weirder still, replacing x, err := might_error() with x, err := 1, nil still errors out with use of untyped nil!
My current line of thinking is that the Error interface is injected into a specific instance of nil in cases where a function's type signature requires it, meaning that it stops being an untyped nil and becomes a typed nil for the lifetime of that specific nil instance, but I'm not at all sure that this is correct since it seems like a strange design choice by nature of it not being clearly generalizeable.
What motivated these design choices? Why have nil be untyped instead of having it be a proper null type, except when it's convenient, at which point it becomes a typed value implementing an Error interface (to the best of my understanding)?
This is a complete non-problem in the sense that in practice there can be confusion if a nil value is stored in an interface variable making that variable non-nil. This is https://golang.org/doc/faq#nil_error and everyone is bitten a few times by this problem until you learn that interface values containing a nil variable are no longer nil themself. It's a bit like with var s = []*int{nil, nil, nil} where s contains only nils but is non-nil itself.
Technically (from a language design point) you could introduce several "nils", e.g. nil for pointers, null for interfaces, noop for functions and vac for channels. (Exaggerating a bit). With this you could have:
type T whatever
func (t *T) Error() string // make *T implement error
var err error // interface variable of type error
print(err == null) // true, null is Zero-Value of interface types
print(err == nil) // COMPILER ERROR, cannot compare interface to nil (which is for pointers only
var t *T = nil // a nil pointer to T
err = t // store nil *T in err
print(err == null) // false err is no longer null, contains t
You could even remove the compiler error:
err = t // store nil *T in err
print(err == null) // false, err contains t
print(err == nil) // "deep" comparison yielding true
err = &T{} // store non-nil *T in err
print(err == null) // still false
print(err == nil) // false, value inside err is no longer nil
You also could define a default type for nil, e.g. *[]chan*func()string so that you can write x := nil like you can do with f := 3.141 where the default type of the untyped constant 3.141 is float64. But such a default type for nil would be arbitrary and not helpful at all (as my example shows; *[]chan*func()string is uncommon).
If I remember correctly there was a longer discussion about this topic on the golang-nuts mailng list where the rationals about this design was discussed. It boiled down to something like: "The actual real-life problems with having nil multiple meanings and not being a constant are tiny (basically just variants of an error type containing nil not being nil). The 'solution' to this one tiny problem would complicate the language (e.g. by introducing a null literal for the zero value of interface types) considerably. It probably is simpler to teach people that interface values containing a nil are no longer nil themself than introducing typed nils or nulls for interface types."
In more than 10 years of programming in Go I literally never had to think about a nil literal being typed or untyped or constant or whatever. The article you probably are referring to is constructing pure academic, but actually non-problem in practice issue out of a tiny design decision about having just one nil literal for all zero values for pointer, slice, map, channel and function types.
Addendum
First, even though nil is typeless on paper, it takes on the error type (by way of it implementing the Error interface combined with Go's duck typing) for the purposes of conforming to might_error's return type signature.
This is a completely wrong description of what happens.
If you write
func f() (r int) { return 7 }
then 7 is assigned to r of type int and f returns. This works because 7 can be assigned to int.
In
func might_error() (int, error) { return 1, nil }
the same happens, the second return variable of type error (an interface type) is set to nil because nil can be assigned to any interface type like you can assign nil to any pointer type or any function type.
This has nothing to do with "implementing the Error interface combined with Go's duck typing". Absolutely not. nil doesn't implement the error interface at all. Any interface value can be nil like can be any function value or slice value or channel value. Setting a chan to nil basically "clears" the channel variable, it doesn't mean that nil somehow "implements the channel interface". You seem to conflate the zero value of several types and how to set them by assigning nil with implementing interfaces. All this has basically nothing to do with nil being typed or not. The nil literal in source code os overloaded and often can be thought of as just representing the zero value of a type.
Your example doesn't compile (because main needs to return nothing), and when you go into picky and nitty areas of a language, all your examples should actually work. 😀
My current line of thinking is that the Error interface is injected into a specific instance of nil in cases where a function's type signature requires it ...
That's not quite right. The Go specification tells us how this works:
There are three ways to return values from a function with a result type:
The return value or values may be explicitly listed in the "return" statement. Each expression must be single-valued and assignable to the corresponding element of the function's result type. [example snipped]
This is the method you use in your example program (which I cleaned up a bit to compile and run in the Go Playground). The expression:
return 1, nil
means:
unnamed_return_variable_1 = 1
unnamed_return_variable_2 = nil
where the two unnamed return variables don't actually have these names (they're un-named, after all) but do have types, courtesy of the declaration of the function. So
return 1, nil
is not at all like:
x, err := 1, nil
but rather more like:
var x int; var err error; x, err = 1, nil
which, as you can see, is also quite valid.
What motivated these design choices?
For that, you'd have to ask the designers.
ThinkGoodly mentions in a comment that:
The untyped 0 does not cause this angst.
The untyped constant 0 has a default type, though:
An untyped constant has a default type which is the type to which the constant is implicitly converted in contexts where a typed value is required, for instance, in a short variable declaration such as i := 0 where there is no explicit type. The default type of an untyped constant is bool, rune, int, float64, complex128 or string respectively, depending on whether it is a boolean, rune, integer, floating-point, complex, or string constant.
The predeclared identifier nil has no type, not even a default type. It just has a series of special rules that allow it to be used in various places.
The non-language-canon way to think about this
While this isn't how it's defined (it's defined by the Go specification), this is how I recommend thinking about the issue:
The predeclared identifier1 nil is untyped.
There are typed nil values. Anything sufficiently pointer-like can be nil, or can be non-nil. For instance, any *int variable can be pointer-to-int-nil, as an uninitialized one is. This nil is not the nil "keyword" (predeclared identifier, see footnote); it's a completely different "nil", just like Bruce (Banner) is a completely different person from Bruce (Wayne).
Interface values are two part: a type, and a value of that type. The type can be nil! This is yet another kind of nil, different from nil (the untyped "keyword") and nil (some particular nil of some particular pointer-y type). If the type is nil, the value can also be nil. If both are nil, the interface value compares equal to the <nil,nil> pair that the untyped "keyword" nil turns into when needed for comparison against an interface value. If either one is non-nil, the comparison says these are not equal. The hardware implementation is that the two parts of the interface are both zero: if either part is nonzero, the thing as a whole is nonzero, and hence "not nil".
The conversion from nil-the-"keyword" (predeclared identifier) to an appropriate hardware style zero value occurs when there's enough information supplied by context. Assignment to some variable—even an unnamed one—supplies context. Assignment to some positional argument supplies context. Trying to use a short declaration fails to supply context, hence the error.
1Go in general favors predeclared identifiers to keywords, so that false and true and so on are not actually keywords. This keeps nil out of the keyword set as well. Nonetheless, some things—such as the boolean constants false and true, or the magical behavior of the predeclared identifier iota, are only accessible by not covering up the predeclared identifier and then using it. That is, if you name something iota, you can't get the iota style functionality until that name goes out of scope. The way these things behave is often handled via keywords in other languages. If you tend to think in, say, C++ or Java, you might want to keep reminding yourself that these aren't keywords, even though they smell like them.
Golang supports assigning multiple return values to multiple left hand side variables. E.g:
func test() (string, string) {
return "1", "1"
}
a, b := test()
or
a, _ := test()
and the number of receiving variables and return values must match:
b = test() //wrong
But for some built-in types, such as [] or <-, a variable number of return values are supported
key, exist := map[key]
key := map[key]
I can read value from channel like this
c <- myChan
c, exist <- myChan
How can we explain the inconsistency? Is this a capability reserved to the core go runtime/language?
This behavior clearly specified in the golang specification:
Receive operator
A receive expression used in an assignment or initialization of the special form
x, ok = <-ch
x, ok := <-ch
var x, ok = <-ch
var x, ok T = <-ch
yields an additional untyped boolean result reporting whether the communication succeeded. The value of ok is true if the value received was delivered by a successful send operation to the channel, or false if it is a zero value generated because the channel is closed and empty.
Index expression
An index expression on a map a of type map[K]V used in an assignment or initialization of the special form
v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
var v, ok T = a[x]
yields an additional untyped boolean value. The value of ok is true if the key x is present in the map, and false otherwise.
Assignments
A tuple assignment assigns the individual elements of a multi-valued operation to a list of variables. There are two forms. In the first, the right hand operand is a single multi-valued expression such as a function call, a channel or map operation, or a type assertion. The number of operands on the left hand side must match the number of values. For instance, if f is a function returning two values,
x, y = f()
assigns the first value to x and the second to y. In the second form, the number of operands on the left must equal the number of expressions on the right, each of which must be single-valued, and the nth expression on the right is assigned to the nth operand on the left.
Therefore as you can see this behavior being specified by language design and you cannot achieve those specified for Receive operator and Index expression by yourself.
You are confusing multiple values returned from a function with the so-called "comma ok" idiom.
With a function's return values you must either handle all of them, or none of them. Simple.
"Comma ok" is more subtle. Often the behavior is changed if you have a second value specified. Consider these statements:
v, ok := x.(int)
// vs
v := x.(int)
If x is an interface holding an integer, all is well, however, if x holds a different type the first statement will work (returning 0, false), and the second one will panic.
Each type of statement with a "comma ok" form is a different special case, and they are not the same as other kinds of multiple assignments (such as multiple function return values). You cannot compare them, each is its own thing, with its own rules.
Need to check if parameter being passed to func is nil and return 0.
Below is my intended code
func (t *Transaction) GetOperationCount(input bean.Request) (int, error) {
var result int = 0
if input == nil { //error here
return result, nil
}
// Other code here!!!!
return result, nil
}
bean.Reques is a struct.
However it had issue: "cannot convert nil to type bean.Request input Request". I have trying
if (bean.Request{})== input
But it gives :
"json:\"MV_STATUS\""; NDFNFFP string "json:\"NDF_NFFP\""; NDFNFMV string "json:\"NDF_NFMV\"" } "json:\"attr\"" } "json:\"marke
t_value\"" } "json:\"market_values\"" } "json:\"tick\"" } "json:\"insertion\"" } "json:\"operation\"" } "json:\"transaction\""
} cannot be compared)
Should I change the parameter to "input *bean.Request" ?
Short answer: Yes, here is the working version:
func (t *Transaction) GetOperationCount(input *bean.Request) (int, error) {
var result int = 0
if input == nil {
return result, nil
}
// Other code here
return result, nil
}
You have some options (depending to your use case, see: Pointers vs. values in parameters and return values):
1- You may use pointer (input *bean.Request) and compare it with nil
2- you may use another struct and compare it with reflect.DeepEqual(r, zero)
3- You may write your own compare function (or method with pointer or value receiver)
See this sample (try it on The Go Playground):
package main
import (
"fmt"
"reflect"
)
func (t *Transaction) GetOperationCount(input *Request) (int, error) {
var result int = 0
if input == nil {
return result, nil
}
// Other code here
return result, nil
}
func main() {
var input *Request
if input == nil {
fmt.Println("input is nil.") //input is nil.
}
input = &Request{}
if input != nil {
fmt.Println("input is not nil.") //input is not nil.
}
r := Request{}
fmt.Printf("Zero value: %#v\n", r) //Zero value: main.Request{I:0}
zero := Request{}
fmt.Println("r == zero :", r == zero) //r == zero : true
fmt.Println("DeepEqual :", reflect.DeepEqual(r, zero)) //DeepEqual : true
fmt.Println("compare :", compare(&r, &zero)) //compare : true
}
func compare(r, zero *Request) bool {
return r.I == zero.I
}
type Request struct {
I int
}
type Transaction struct{}
output:
input is nil.
input is not nil.
Zero value: main.Request{I:0}
r == zero : true
DeepEqual : true
compare : true
Comparison operators:
4- You may compare it with its zero value (nil for pointers, and if it is struct it's zero value is Empty struct if it is like struct{} (not nil), or struct with all fields initialized to their zero values):
The zero value:
When storage is allocated for a variable, either through a declaration
or a call of new, or when a new value is created, either through a
composite literal or a call of make, and no explicit initialization is
provided, the variable or value is given a default value. Each element
of such a variable or value is set to the zero value for its type:
false for booleans, 0 for integers, 0.0 for floats, "" for strings,
and nil for pointers, functions, interfaces, slices, channels, and
maps. This initialization is done recursively, so for instance each
element of an array of structs will have its fields zeroed if no value
is specified.
These two simple declarations are equivalent:
var i int
var i int = 0
After
type T struct { i int; f float64; next *T }
t := new(T)
the following holds:
t.i == 0
t.f == 0.0
t.next == nil
The same would also be true after
var t T
See "reflect.DeepEqual": How to compare struct, slice, map are equal?
func DeepEqual(x, y interface{}) bool
Docs:
DeepEqual reports whether x and y are ``deeply equal,'' defined as follows.
Two values of identical type are deeply equal if one of the following cases applies.
Values of distinct types are never deeply equal.
Array values are deeply equal when their corresponding elements are deeply equal.
Struct values are deeply equal if their corresponding fields,
both exported and unexported, are deeply equal.
Func values are deeply equal if both are nil; otherwise they are not deeply equal.
Interface values are deeply equal if they hold deeply equal concrete values.
Map values are deeply equal if they are the same map object
or if they have the same length and their corresponding keys
(matched using Go equality) map to deeply equal values.
Pointer values are deeply equal if they are equal using Go's == operator
or if they point to deeply equal values.
Slice values are deeply equal when all of the following are true:
they are both nil or both non-nil, they have the same length,
and either they point to the same initial entry of the same underlying array
(that is, &x[0] == &y[0]) or their corresponding elements (up to length) are deeply equal.
Note that a non-nil empty slice and a nil slice (for example, []byte{} and []byte(nil))
are not deeply equal.
Other values - numbers, bools, strings, and channels - are deeply equal
if they are equal using Go's == operator.
In general DeepEqual is a recursive relaxation of Go's == operator.
However, this idea is impossible to implement without some inconsistency.
Specifically, it is possible for a value to be unequal to itself,
either because it is of func type (uncomparable in general)
or because it is a floating-point NaN value (not equal to itself in floating-point comparison),
or because it is an array, struct, or interface containing
such a value.
On the other hand, pointer values are always equal to themselves,
even if they point at or contain such problematic values,
because they compare equal using Go's == operator, and that
is a sufficient condition to be deeply equal, regardless of content.
DeepEqual has been defined so that the same short-cut applies
to slices and maps: if x and y are the same slice or the same map,
they are deeply equal regardless of content.
Yes..The error itself mentions that it cannot compare both. You can use pointer to compare with nil or create an empty struct to compare.
There are many cases using nil in golang. For example:
func (u *URL) Parse(ref string) (*URL, error) {
refurl, err := Parse(ref)
if err != nil {
return nil, err
}
return u.ResolveReference(refurl), nil
}
but we can't use it like this:
var str string //or var str int
str = nil
the golang compiler will throw a can't use nil as type string in assignment error.
Looks like nil can only be used for a pointer of struct and interface. If that is the case, then what does it mean?
and when we use it to compare to the other object, how do they compare, in other words, how does golang determine one object is nil?
EDIT:For example, if an interface is nil, its type and value must be nil at the same time. How does golang do this?
In Go, nil is the zero value for pointers, interfaces, maps, slices, channels and function types, representing an uninitialized value.
nil doesn't mean some "undefined" state, it's a proper value in itself. An object in Go is nil simply if and only if it's value is nil, which it can only be if it's of one of the aforementioned types.
An error is an interface, so nil is a valid value for one, unlike for a string. For obvious reasons a nil error represents no error.
nil in Go is simply the NULL pointer value of other languages.
You can effectively use it in place of any pointer or interface (interfaces are somewhat pointers).
You can use it as an error, because the error type is an interface.
You can't use it as a string because in Go, a string is a value.
nil is untyped in Go, meaning you can't do that:
var n = nil
Because here you lack a type for n. However, you can do
var n *Foo = nil
Note that nil being the zero value of pointers and interfaces, uninitialized pointers and interfaces will be nil.
nil is also a value but only difference is- it is empty.
In Javascript for the un-initialized variable will be undefined. In the same way Golang has nil as default value for all the un-initalized data types.
nil in Go means a zero value for pointers, interfaces, maps, slices, and channels.
It means the value is uninitialized
For the data types like slice and pointers which "refer" to other types, "nil" indicates that the variable does not refer to an instance (equivalent of null pointer in other languages)
It is thee zero value of the variables of type functions, maps, interfaces, channels and structures
nil is a predeclared identifier in Go that represents zero values for pointers, interfaces, channels, maps, slices and function types.
nil being the zero value of pointers and interfaces, uninitialized pointers and interfaces will be nil.
In Go, string can’t be nil. A string doesn’t qualify to be assigned nil.
a := nil // It will throw an error 'use of untyped nil'
var a *int = nil //It will work
In Go nil is predeclared identifier that represents nothing for pointers, interfaces, channels, maps, slices and function types. Uninitialized pointers and interfaces will be nil. A string doesn’t qualify to be either of the above-mentioned types and hence can’t be assigned nil.
If you declare a variable by shorthand decleration like this: variable:=nil this will give compile time error because compiler has no idea which type it has to assign to variable .
In Go map, slice and function doesn't support comparison but can be compared with nil.
If any two map, slice or function are assigned to nil and compared with each other then it will raise runtime error.
But if we assign nil to any two pointer variables and compare them with each other then no error will occur.
package main
import (
"fmt"
)
func main() {
var i *int =nil
var j *int =nil
if i==j {
fmt.Println("equal")
} else {
fmt.Println("no")
}
}
This code works fine and prints output as equal.
In Golang, datatype can use nil is pointers, interfaces, maps, slices, channels, function types and errors
in String value is ""
in INT value is ZERO
In Golang, zero value is the default value for defined variables. The default value of different datatypes are:
0 for integer types
0.0 for floating types
false for boolean types
"" for string types
nil for interfaces, slices, channels, maps, pointers and functions
So, nil is the zero value or default value for interfaces, slices, channels, maps, pointers and functions.
For example,
var a int
var s []int
var s1 []int = []int{1, 2}
fmt.Println(a == nil) // throw error
// invalid operation: a == nil (mismatched types int and untyped nil)
fmt.Println(s == nil) // true
fmt.Println(s1 == nil) // false
Since error is an interface, we can write
_, err := Parse("")
if err != nil { // if there is an error
// handle error
}
I have read some text regarding nil slice vs empty slice. I believe I have some basic understanding of the differences between them.
Summary of my understanding: var instance []Type is nil slice and instance == nil returns true; while instance:=[]Type{} is empty slice and instance != nil
However this particular instance still puzzles me.
Please look at the link below for code. My question is the last 2 cases.
https://play.golang.org/p/udyHoOlSeP
Suppose I want to compare two slices, renamed type and interface matching and all. The instance where a receiver can be nil, even though it's not defined as copy by value; while the argument is copied by value, seems to
be non-nil as long as the argument is not untyped.
In the last 2 cases, receiver has been identified as nil while argument is being processed by := so it becomes an empty slice. (But the other == nil also reports false...) How can I fix this to satisfy the following requirement?
nilslice.Equals(nilslice) // -> true
Further, I tried to define another interface comparing to pointers of interface but failed. Compiler complains that
cannot use p (type *AnotherNullable) as type *PointerComparable in argument to AnotherNullable(nil).Equals:
*PointerComparable is pointer to interface, not interface
https://play.golang.org/p/wYO1GKcBds
How can I fix that?
EDIT: Thanks to #zippoxer for all the insights. I learned a lot. I hope new readers too, please don't forget to check out #zippoxer's comment in the answer too!
First, you don't need a pointer to an interface. An interface is already a pointer.
See Go: What's the meaning of interface{}?
Just change the Equals method to accept a PointerComparable instead of a *PointerComparable. Equals will accept an interface instead of a pointer to an interface, but you can still pass a pointer to a slice/whatever to it.
See https://play.golang.org/p/e_Gtq2oAFA
Second, the receiver Nullable isn't an interface, while the argument you pass to Equals is an interface. That would explain why the Nullable receiver stays nil and the Comparable argument isn't nil although it's underlying slice is. The thing is, the Comparable argument is an interface that points to something, so whatever it points to, it won't be nil.
This code explains the problem:
var a interface{}
fmt.Println(a == nil) // true, the interface doesn't point to anything
var someNilSlice []int
fmt.Println(someNilSlice == nil) // true, just some nil slice
a = someNilSlice
fmt.Println(a == nil) // false, now the interface does point to something