Reputation: 42
I have the following code-snippet:
type F func()
type I interface {}
func A() {}
func B() {}
func test() {
var a interface{} = A
var b interface{} = B
if A == B { // 1. Compile error
// Code
}
if a == b { // 2. No compile error
// Code
}
}
If functions are not comparable and interfaces are comparable, why can I assign a function to an interface type?
--
To clarify my question another code-snippet:
type I interface {
DoSomething()
}
type F func()
func (f F) DoSomething() {
f()
}
func A() {
fmt.Println("A")
}
func B() {
fmt.Println("B")
}
func test() {
var _a F = A
var _b F = B
var a I = _a
var b I = _b
if a == b { // 2. No compile error but panic
// Code
}
}
It seems to me, that I can break the type system with simple assignments.
I do not propose that functions should be comparable. My questions are:
Upvotes: 0
Views: 138
Reputation: 55443
To cite Ian Lance Taylor's message from this thread on the Go mailing list:
On Wed, Nov 23, 2016 at 7:00 AM, T L wrote:
On Wednesday, November 23, 2016 at 10:35:59 PM UTC+8, Axel Wagner wrote:
So, your suggestion is, to have functions be comparable, but have the comparisons always be false (unless compared to nil)? How would that be useful and not completely confusing? e.g. how would that not lead to people asking here, once a week, why (
os.Open == os.Open) == false
or something like that?No, I don't
os.Open != os.Open
, they are the same question, so they are equal.Even this seemingly simple statement is unclear. Go now supports
-buildmode=shared
and-linkshared
, meaning that a Go program can link against a set of shared libraries that are themselves written in Go. When running in this mode, a function likeos.Open
can easily appear multiple times in a single program image, in different shared libraries. So whileos.Open == os.Open
might reasonably always be true, givenfunc F() func(string) (*os.File, error) { return os.Open }
then it is much less clear whether
F() == os.Open
should be true, as
F
might be in a shared library and might return a pointer to a different instance ofos.Open
.
And that's just one of the reasons. See another one—regarding the function values which are closures with the same code but closed over different variables— explained in that same thread by Jesper Louis Andersen.
I would add that the whole thread is worth thorough reading and absorbing.
Upvotes: 2
Reputation:
This is simply how the language is defined. From the spec:
Interface values are comparable. Two interface values are equal if they have identical dynamic types and equal dynamic values or if both have value
nil
.
A comparison of two interface values with identical dynamic types causes a run-time panic if values of that type are not comparable.
function values are not comparable. However, as a special case, a [...] function value may be compared to the predeclared identifier
nil
.
That explains why the first if
statement in your example fails at compile time, and why the second one fails at runtime.
Upvotes: 5