Introduction
I came across this topic during my internship at Viant when I was figuring out how to compare errors while unit testing, i.e., how do I check if the expected error and actual error are the same.
Comparing Interfaces
Interface types that are not type parameters are comparable. Two interface values are equal if they have identical dynamic types and equal dynamic values or if both have value nil [1]
I do not completely understand what the first statement means. If you are reading this, and you do, then please reach out to me and help me understand it better!
Let’s break the second statement down to understand it better -
- Static Type vs. Dynamic Type
There is an excellent article [2] that helped me understand this clearly.
Let me explain the difference in simple terms. Consider this -
type I interface {
f() int
}
type A struct {
MemberA int
}
func (a A) f() int {
return a.MemberA
}
type B struct {
MemberB int
}
func (b B) f() int {
return b.MemberB
}
As you can see, there is an interface I
and A
and B
implement I
.
Now,
var x I // the static type of x is I
x = A{1} // the dynamic type of x is A
x.f() // dispatches func f of A
x = B{2} // the dynamic type of x is now B
x.f() // dispatches func f of B
The static type of a variable is known at compile time and never changes. However, as shown above, the dynamic type can change. I personally think of dynamic type as the runtime polymorphism in Java.
- Dynamic Value
Dynamic value is the value assigned to a variable at runtime. In the example above, the variable x
first has a dynamic
value of A{1}
and then has a dynamic value of B{2}
- Putting it all together
Now that we know what terms Dynamic Type and Dynamic Value mean, it is easy to understand how interfaces
are compared. Either the interfaces should be nil
or they should have identical dynamic type and dynamic value.
References
[1] https://go.dev/ref/spec#Comparison_operators
[2] https://avilay.rocks/go-dynamic-types/