31

How would I get a positive test for bar and foo's equality?

 foo = function() {
    a = 1;
 }; 

 bar = function() {
    a = 1;
 }; 

 if (foo === bar) alert('baz');
 if (foo == bar) alert('qux');

Both the above conditionals are false.

Updated - As requested the reason I need to test for function equality

I am building a Publish/Subscribe framework and need to pass the callback inorder to unsubscribe to a topic.

Please see the fiddle: http://jsfiddle.net/jamiefearon/hecMS/47/

5
  • May be you meant for the functions to return a value?? return a; missing? Commented Aug 31, 2012 at 13:41
  • 2
    If you explain why it is you want to do this, it might help people provide helpful answers and comments. Commented Aug 31, 2012 at 13:42
  • So you want to check whether the contents of two functions is exactly the same? Why exactly do you need to do this? Commented Aug 31, 2012 at 13:42
  • Pointy - I've updated my answer Commented Aug 31, 2012 at 13:57
  • Your fiddle should work fine as long as the callback you pass to unsubscribe is reference equal to the one you pass in subscribe. Isn't this the way most JS event pub/sub libraries work? What's the problem with that approach? Commented Sep 30, 2016 at 20:21

7 Answers 7

43

You could check whether the content of two functions is exactly the same by comparing the result of calling toString on them

 var foo = function() {
    a = 1;
 }; 

 var bar = function() {
    a = 1;
 }; 

alert(foo.toString() == bar.toString());​

That will, however, fail if there is but one character that is different. Checking to see if two functions do the same thing, on the other hand, is pretty much impossible.

Sign up to request clarification or add additional context in comments.

7 Comments

You are correct. Perfectly worked...
But this is also perfectly useless.
absolutely not! It is essential for functions like lodash debounce.
Beware that this may return a false positive – if your functions refer to any variables defined in their containing scope, they could have the exact same source code but behave differently. See this answer for an example.
const delayedOnSave = useCallback( debounce((val) => onSave(val), 150), [onSave.toString()] );
|
27

The problem is that there're different notions of equality on functions.

  • Reference equality. Functions are stored somewhere in memory, and start from a certain address. For two function names (which are essentially addresses inside) reference equality gives you true iff both names point to the same address. It's a matter when you assign one bar = foo. Reference equality is used in JavaScript.
  • Equality on source code as proposed in another answer. It won't work, if you change any character in function body. Also, toSource is currently (as of 2014) only available in Firefox, as it's not W3C standardized.
  • Syntactic equalities on source code. One could use abstract syntax trees to resist against modifications in spaces and comments. One could use alpha-equivalence (i.e. equivalence of functions, where variables are consistently renamed) as defined in lambda calculus, but also there is
  • Extensional equality, when functions are equal if they work the same way. There's a theorem stating that there's just no algorithm to check for extensional equality of functions, so it's certainly not the one you're searching for. Though, in some more advanced languages than JS there are
  • Intensional equality (where you either prove that functions are equal by hand or your program doesn't compile) and
  • Observational equality (this one is too advanced to explain).

So, take care of what you think equality is.

5 Comments

If you could add an example for each of those, then it would make this a great answer!
Assuming a function has no contextual/free variables, a language could pretty trivially allow authors to losslessly convert between a potent "program" (a function) and impotent "data" (like a string or AST which could be parsed back into that same function). This could be very useful, because syntactic equality implies both equality of results ("extensional equality") and equality of process ("intentional equality"). You could take a cue from Python's distinct keyword/operator for reference equality, is, and introduce a new one for function syntactic equality: does.
If you wanted to have a really nice interface, your language could give an error any time you try to call == with functions as arguments, saying something to the effect of: "When comparing functions, you must use refers to for reference/memory equality, or does for syntactic equality. It's mathmatically impossible to check for equality of results [wiki link]."
@iono Of course, languages must not allow referential equality by default, precisely because it breaks referential transparency. Usually you really want to work with ref-transparent systems, because they allow easy refactoring and deduction of properties of a program through equational reasoning.
So yes, it's quite surprising doing == and even === on functions is not obsolete, and that equality on objects doesn't do checks field by field with hashconsing.
3

You can test to see whether two variables refer to the exact same function object, and you can convert functions to strings and see if they're really exactly the same, but trying to determine whether two functions do the exact same thing would be a little harder, or maybe a lot harder.

Running a pair of functions through a minifier would be interesting, because minifiers do a considerable amount of static analysis.

6 Comments

Not a little harder, but actually impossible.
@duri well I've learned around here that saying out lout that something is "impossible" is a good way to be humiliated :-) However I agree with you, in general, because complete static analysis of a dynamic language like JavaScript is not possible.
Well, the question whether 2 functions are equivalent is related to mathematics rather than to programming but you may be interested in stackoverflow.com/questions/1132051/…
@duri that's interesting, but I think (perhaps incorrectly) that having access to the actual makeup of a function is different than the problem of deciding equivalence of two "opaque" functions. For example, it's certainly possible to say that two JavaScript functions that, when stringified, are character-for-character the same are therefore equivalent, to the extent that the behavior of the runtime can be assumed to be consistent.
@Pointy I believe this to be incorrect. If you have two functions which are identical character-for-character then they still may operate differently because they may reference variables in their static closure. e.g. function() { return x } will return differently depending on what x is in the scope where the function is defined.
|
3

If you look at the Node.js source for events

https://github.com/nodejs/node/blob/master/lib/events.js

you can see that the core team uses === to compare functions for equality.

I am not sure how === is implemented for functions, but I sure hope it's not toString(), since two different functions might have the same toString() result.

1 Comment

This uses a reference equality check, same as javascript's standard behavior: github.com/nodejs/node/blob/master/lib/events.js#L329
1

Basically, it's impossible in general. There is no way to test functional equality in javascript. The closest you can get is either compare their code as string for equality.

3 Comments

this is apparently incorrect
It's not impossible in general. It's impossible to write an algorithm to compare any two potentially different functions to check if their set of results are equal, but if the instructions/code are equal, and any contexts that code executes in are equal, then that guarantees the results will be equal.
But that "context" will include stuff such as call stack, and it can have arbitrarily complicated data structures with cyclic references between objects, references to native objects with no good notion of equality (DOM nodes or file descriptors) etc. The only context where function equality is somewhat possible is if you have a language with dependent types, and you have to provide both equality algorithm on functions as well as BHKish proof that the thing it computes is actually an equality.
1

It seems like if you need this functionality, it might be better to restructure your program a bit. Something like this could work:

function baz(myInt) { return 3 + myInt; }
function asd(a) { return 3 + a; }

var foo = baz;
foo(1); //returns 4

var bar = baz;
bar(3); //returns 6

foo === bar; //true

bar = asd;
bar(3); //returns 6

foo === bar; //false

Comments

0

Simple approach: If you implement your subscribe API to return a unique ID every time it is invoked, then it will be as simple as invoking unsubscribe API with that ID. Internally in simple scenario you would use a simple array to store all subscribers but with this approach you will have to store. An ID can be a simple counter that you can increment with every single subscribe call.

{ID: subscriber' callback function}

So iterate over all subscribers when you want to publish to all subscribers.

Advanced approach: Instead of accepting a simple function name in subscribe API, accept an object of a class which should have an onMessage function (or whatever name you want to give this method). Then you can simply pass same instance of object to unsubscribe API to get yourself unregistered. When you need to notify subscriber you can invoke instance.onMessage function of all subscribers. Comparing two object reference is easy.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.