Note that there is a difference between equality and identity. The operators ==
and !=
in Go1 are comparing the values for equivalence (except when comparing channels), not for identity. Because these operators are trying not to mix equality and identity, Go1 is more consistent than pre-Go1 in this respect.
Function equality is different from function identity.
One reason for not allowing ==
and !=
on function types is performance. For example, the following closure is not using any variables from its environment:
f := func(){fmt.Println("foo")}
Disallowing comparisons of functions enables the compiler to generate a single implementation for the closure, instead of requiring the run-time to create a new closure (at run-time). So, from performance viewpoint the decision to disallow function comparisons was a good decision.
In relation to using the reflect
package to determine function identity, a code like
func SomeFun() {}
func AnotherFun() {}
func main() {
sf1 := reflect.ValueOf(SomeFun)
sf2 := reflect.ValueOf(SomeFun)
fmt.Println(sf1.Pointer() == sf2.Pointer()) // Prints true
af1 := reflect.ValueOf(AnotherFun)
fmt.Println(sf1.Pointer() == af1.Pointer()) // Prints false
}
relies on undefined behavior. There are no guarantees as to what the program will print. The compiler may decide that it will merge SomeFun
and AnotherFun
into a single implementation, in which case the 2nd print statement would print true
. In fact, there is absolutely no guarantee that the 1st print statement will print true
(it may, under some other Go1 compiler and run-time, print false
).
A correct answer to your original question is:
package main
import "fmt"
func F1() {}
func F2() {}
var F1_ID = F1 // Create a *unique* variable for F1
var F2_ID = F2 // Create a *unique* variable for F2
func main() {
f1 := &F1_ID // Take the address of F1_ID
f2 := &F2_ID // Take the address of F2_ID
// Compare pointers
fmt.Println(f1 == f1) // Prints true
fmt.Println(f1 == f2) // Prints false
}