Equate non-native functions that have the same code. #12
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Previously, function objects were regarded as equal by
@wry/equality
only if they were===
to each other. This policy was overly restrictive in many common situations, such as when comparing functions that are repeatedly passed as fresh function expressions within objects that are otherwise deeply equal.Thanks to this PR, the
@wry/equality
package now considers non-native functions equal if they are===
(as before) or if they have the same code according toFunction.prototype.toString
. For native functions, we must check===
because their code is censored, e.g.Object.assign.toString() === "function assign() { [native code] }"
.Note that this behavior is not entirely sound, since
!==
function objects with the same code can behave differently depending on their closure scope. However, any function can behave differently depending on the values of its input arguments (includingthis
) and its calling context (including its closure scope), even though the function object is obviously===
to itself; and it is entirely possible for functions that are not===
to behave exactly the same under all conceivable circumstances.Because none of these factors are statically decidable in JavaScript (or any Turing-complete programming language, probably?), JS function equality is simply not well-defined. This ambiguity allows us to consider the best possible heuristic among various imperfect options, and equating non-native functions that have the same code has enormous practical benefits (see apollographql/apollo-client#6588, for example).
I considered making this behavior configurable, until I realized that strict
===
equality was never an absolute guarantee of behavioral equivalence, anyway. Ambiguities can be liberating!