Comments (6)
Both of those are function pointers. Functions in Go are not comparable (as defined in the language spec). In this situation, cmp.Equal
took the same definition as reflect.DeepEqual
with regard to function pointers where they are only equal if both are nil, otherwise they are never equal.
Even though both appear to have the same pointer, that is actually an implementation detail of the current Go compiler. For top-level functions, a pointer has a well-defined meaning. However, when you derive a function pointer from a method or closure, the meaning becomes more hazzy.
func MakeClosure() func() int {
var x int
return func() {
x++
return x
}
}
f1 := MakeClosure()
f2 := MakeClosure()
f1 == f2 // Suppose this were possible, what should this return?
from go-cmp.
That seems highly suspect. See golang/go#18871.
Comparing the reflect.Value
directly also compares the reflect.flags
type, which is entirely an implementation detail of the "reflect" package.
from go-cmp.
This is behaving as intended. reflect.Type
is a good example of a type that should not be compared by deeply descending into it since it contains state that it not safe to compare.
The user should be explicit about the proper way to compare reflect.Type
:
cmp.Comparer(func(x, y reflect.Type) bool { return x == y })
Sometimes pointer comparisons are the right approach, other times the right approach is to descend into the value. reflect.DeepEqual
is inconsistent in that it only does pointer comparison if they are identical, otherwise it descends. cmp.Equal
chose to always descends into pointers.
We chose the current behavior for the following reasons:
- Always descending is more expressive, since you could always "opt-out" of it by providing a custom
Comparer
to do pointer comparison. The opposite is not true. - There exists comparisons in Go that are irreflexive (e.g.,
NaN != NaN
or comparisons on function pointers). Thus, performing pointer comparison hides the fact that the underlying values may actually be unequal by other rules of comparison (see this example). Personally, I'm not fond of irreflexive equalities, but they exist and I prefer to keep the number of exceptions lower.
from go-cmp.
Here's an example of how an option can be used to obtain the equivalent behavior of reflect.DeepEqual
with regard to pointers:
func EquateIdenticalPointers() cmp.Option {
return cmp.FilterPath(func(p cmp.Path) bool {
// Filter for pointer kinds only.
t := p.Last().Type()
return t != nil && t.Kind() == reflect.Ptr
}, cmp.FilterValues(func(x, y interface{}) bool {
// Filter for pointer values that are identical.
vx := reflect.ValueOf(x)
vy := reflect.ValueOf(y)
return vx.IsValid() && vy.IsValid() && vx.Pointer() == vy.Pointer()
}, cmp.Comparer(func(_, _ interface{}) bool {
// Consider them equal no matter what.
return true
})))
}
Note that this option will conflict with another option that is applicable on *T. See #36 for a proposed solution around that. With #36, you could always wrap inside testify
as such:
return cmp.Diff(x, y,
DeepAllowUnexported(x ,y),
cmp.FilterOrder(
cmp.Options(userOpts), // User-provided options take precedence
EquateIdenticalPointers(),
),
)
from go-cmp.
I see
Thank you very much for the detailed explanation.
Make sense all that you said here.
One last thing that is not very clear to me.
Can you explain why the comparison failed? the diff looks like they are identical:
{*reflect.rtype}.alg.hash:
-: (func(unsafe.Pointer, uintptr) uintptr)(0x451530)
+: (func(unsafe.Pointer, uintptr) uintptr)(0x451530)
{*reflect.rtype}.alg.equal:
-: (func(unsafe.Pointer, unsafe.Pointer) bool)(0x401a50)
+: (func(unsafe.Pointer, unsafe.Pointer) bool)(0x401a50)
from go-cmp.
@dsnet
It is what @matryer is doing here, right?
https://github.com/matryer/is/blob/master/is.go#L257
The simple function pointer works, closure is not.
It kinda makes sense, as it does have different stack bound to it.
https://go.dev/play/p/IcBdFTMhrgT
from go-cmp.
Related Issues (20)
- Diff is extremely slow HOT 3
- How to ignore specific field by name? HOT 1
- Ideas for a v2 HOT 3
- Default support for the `netip` package HOT 1
- New minor release of the library? HOT 4
- cmp.Diff() switching from property diffs to "new object" diff when object changes significantly HOT 1
- Inconsistent whitespace produced by cmp.Diff HOT 2
- cmpopts: add EquateUnsetFields(want) or FilterFieldsFrom(want) HOT 1
- IgnoreFields and nested struct HOT 2
- Enable a dependency update tool HOT 2
- Package Name Mismatches HOT 4
- unhelpful output for difference in slices HOT 1
- How to implement jests.js's `expect.any(String)` like functionality? HOT 1
- cmpopts.IgnoreFields does not work on structs with an Equal method HOT 1
- Performance Issue Comparing Array Types HOT 1
- Naming clash for new cmp standard package HOT 4
- Comparing two fields with diffirent types that are semantically equivalent HOT 3
- String diff for UUIDs can use strings.Join syntax which makes it more confusing HOT 4
- Reporter truncating important context on diff output but leaving others alone
- How to add more context to Diff output?
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from go-cmp.