Why Don't Methods Have Reference Equality

Why don't methods have reference equality?

Method objects are created each time you access them. Functions act as descriptors, returning a method object when their .__get__ method is called:

>>> What.__dict__['meth']
<function What.meth at 0x10a6f9c80>
>>> What.__dict__['meth'].__get__(What(), What)
<bound method What.meth of <__main__.What object at 0x10a6f7b10>>

If you're on Python 3.8 or later, you can use == equality testing instead. On Python 3.8 and later, two methods are equal if their .__self__ and .__func__ attributes are identical objects (so if they wrap the same function, and are bound to the same instance, both tested with is).

Before 3.8, method == behaviour is inconsistent based on how the method was implemented - Python methods and one of the two C method types compare __self__ for equality instead of identity, while the other C method type compares __self__ by identity. See Python issue 1617161.

If you need to test that the methods represent the same underlying function, test their __func__ attributes:

>>> What.meth == What.meth     # functions (or unbound methods in Python 2)
True
>>> What().meth == What.meth # bound method and function
False
>>> What().meth == What().meth # bound methods with *different* instances
False
>>> What().meth.__func__ == What().meth.__func__ # functions
True

Why does 'is' not work when comparing instance methods in python

methods are implemented as descriptors -- So each time you access the f member, a new function is created. You can see this by looking at their ids...

>>> class A(object):
... def f(self):
... pass
...
>>> a = A()
>>> f1 = a.f
>>> f2 = a.f
>>> id(f1)
4325305232
>>> id(f2)
4325818528

To be a little more clear what I mean when I say that they are implemented via descriptors, the following expressions:

a = A()
func = a.f

are equivalent to:

a = A()
func = A.f.__get__(a, A)

Clearly you don't want to be writing the latter all the time, so the shortcut is pretty nice :-).

With that said, this starts to explain how a bound method knows what self is since a (which is self in the method) gets passed to __get__ which is what constructs the bound method.

Why does the identity of a method does change?

Python doesn't keep canonical method objects. Every time you access a method, you get a newly created method object:

>>> OrderedDict.update is OrderedDict.update
False

Every time you printed the ID of A.f, that was a new A.f object. The fact that old ID values were reused when old objects were deleted is a quirk of the allocator and garbage detector; the storage of recently-released objects is frequently used to represent newly-created objects.

function/method reference equality in scala

Summary:
Yes, it is possible to test for equality between two concrete function references in Scala, but not exactly in the way you stated your problem. You just have to capture the concrete function reference of an object, class or trait (not a lambda, anonymous function, etc.).

Details:
Because Scala does have the notion of a function reference, it is possible to check two different function references for reference equality. And because Scala also provides a mechanism for obtaining a function reference from any valid Scala method, it means you can likely do what you were seeking to do, given your comment question on m-z's answer, "...there is no way to get a reference or something similar for a method?"

The essential thing to remember is that two functions can only be checked for reference equality. IOW, to functions CANNOT be checked for function definition equality (which you don't really want anyway for the Pandora's box of undesired undecidable tangents it would generate).

So, below is how I came to think about it concretely and accurately. I used the Scala (2.11.7) Worksheet within IntelliJ (15.0.3) to create the following test scenarios.

First, the failure pathway, both compile time and run time:

object ConcreteMethods1 {
def intToStringNone(string: String): Option[Int] =
None

def intToStringSome1(string: String): Option[Int] =
Some(1)
}
//def someMethodFailureCompileTime(
// parseFunctionReference: String => Option[Int]
//): (Boolean, Boolean) = {
// (
// parseFunctionReference == ConcreteMethods1.intToStringNone
// , parseFunctionReference == ConcreteMethods1.intToStringSome1
// )
//}
def someMethodFailureRuntime(
parseFunctionReference: String => Option[Int]
): (Boolean, Boolean) = {
val intToStringNoneFunctionReference: String => Option[Int] =
ConcreteMethods1.intToStringNone
val intToStringSome1FunctionReference: String => Option[Int] =
ConcreteMethods1.intToStringSome1
(
parseFunctionReference == intToStringNoneFunctionReference
, parseFunctionReference == intToStringSome1FunctionReference
)
}
val someMethodNoneFailureRuntime =
someMethodFailureRuntime(ConcreteMethods1.intToStringNone)
//want (true, false), but get (false, false)
val someMethodSome1FailureRuntime =
someMethodFailureRuntime(ConcreteMethods1.intToStringSome1)
//want (false, true), but get (false, false)

Second, the success pathway (which implies both compile time and run time):

object ConcreteMethods2 {
def intToStringNone(string: String): Option[Int] =
None

def intToStringSome1(string: String): Option[Int] =
Some(1)

val intToStringNoneFunctionReference: String => Option[Int] =
intToStringNone

val intToStringSome1FunctionReference: String => Option[Int] =
intToStringSome1
}
def someMethodSuccess(
parseFunctionReference: String => Option[Int]
): (Boolean, Boolean) = {
(
parseFunctionReference == ConcreteMethods2.intToStringNoneFunctionReference
, parseFunctionReference == ConcreteMethods2.intToStringSome1FunctionReference
)
}
val someMethodNoneSuccess =
someMethodSuccess(ConcreteMethods2.intToStringNoneFunctionReference)
val someMethodSome1Success =
someMethodSuccess(ConcreteMethods2.intToStringSome1FunctionReference)

And there you have it, testing equality between two concrete function references in Scala. This little trick helped solve a core issue with recursion I had trying to write generic parsing code which had a parsing from a string failover at root. I was able to use this concrete function reference equality trick to properly terminate the recursion.

Value vs. Reference equality in generic ListT.Contains()

Ok, let's handle a few misconceptions first:

By default, .Equals() calls .ReferenceEquals(), so .Contains() will only return true if the list contains the exact same object.

This is true, but only for reference types. Value types will implement a very slow reflection-based Equals function by default, so it's in your best interest to override that.

I can't think of a single case where that would be desirable for a reference type.

Oh I'm sure you can... String is a reference type for instance :)

What I'm hearing from @Enigmativity is that implementing IEqualityComparer<StagingDataRow> will give my typed DataRow a default equality comparer that will be used instead of the default comparer for Object – allowing me to implement value equality logic in StagingDataRow.Equals().

Err... No.

IEqualityComaprer<T> is an interface which lets you delegate equality comparison to a different object. If you want a different default behavior for your class, you implement IEquatable<T>, and also delegate object.Equals to that for consistency. Actually, overriding object.Equals and object.GetHashCode is sufficient to change the default equality comparison behavior, but also implementing IEquatable<T> has additional benefits:

  • It makes it more obvious that your type has custom equality comparison logic - think self documenting code.
  • It improves performance for value types, since it avoids unnecessary boxing (which happens with object.Equals)

So, for your actual questions:

Am I understanding that correctly?

You still seem a bit confused about this, but don't worry :)

Enigmativity actually suggested that you create a different type which implements IEqualityComparer<T>. Looks like you misunderstood that part.

Am I guaranteed that everything in the .NET framework will call EqualityComparer<StagingDataRow>.Equals() instead of StagingDataRow.Equals()

By default, the (properly written) framework data structures will delegate equality comparison to EqualityComparer<StagingDataRow>.Default, which will in turn delegate to StagingDataRow.Equals.

What should IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj) hash against, and should it return the same value as StagingDataRow.GetHashCode()

Not necessarily. It should be self-consistent: if myEqualitycomaprer.Equals(a, b) then you must ensure that myEqualitycomaprer.GetHashCode(a) == myEqualitycomaprer.GetHashCode(b).

It can be the same implementation than StagingDataRow.GetHashCode, but not necessarily.

What is passed to IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj)? The object I'm looking for or the object in the list? Both? It would be strange to have an instance method accept itself as a parameter...

Well, by now I hope you've understood that the object which implements IEqualityComparer<T> is a different object, so this should make sense.


Please read my answer on Using of IEqualityComparer interface and EqualityComparer class in C# for more in-depth information.

Why override equals instead of using another method name

This seems like a silly question but why do we override equals method instead of creating a new method with new name and compare using it?

Because all standard collections (ArrayList, LinkedList, HashSet, HashMap, ...) use equals when deciding if two objects are equal.

If you invent a new method these collections wouldn't know about it and not work as intended.

The following is very important to understand: If a collection such as ArrayList calls Object.equals this call will, in runtime, resolve to the overridden method. So even though you invent classes that the collections are not aware of, they can still invoke methods, such as equals, on those classes.

If I didn't override equals that means both == and equals check whether both references are pointed to same memory location?

Yes. The implementation of Object.equals just performs a == check.

Value equality for struct keys and reference equality for class keys in a dictionary

I can't use neither Object.Equals (only works with structs) nor Object.ReferenceEquals (only works with reference types).

It seems you may simply be mistaken about how these work. The System.Object.Equals() method implementation works equally well (no pun intended) whether dealing with a value type or a reference type.

For value types, it does a field-by-field comparison. If the two values being compared are the same type, and each of their fields have the same value, then they are considered equal.

For reference types, it simply uses reference equality, as you seem to want.

Note that types can override this method, so the actual implementation used could be different from the above. For example, the string type overrides the method, so that two strings which are not the same instance can still compare as equal. But by default, the above is what happens.

Finally I'll note that if what you want is a behavior that works exactly like the Dictionary<TKey, TValue> class, it may well be that the best solution is to just use that class. :)

Are Java method references stable?

JLS makes no promises about identity or equality of what you get out of method reference expressions.

You can run a quick test:

Object obj = new Object();

IntSupplier foo = obj::hashCode;
IntSupplier bar = obj::hashCode;

System.out.println(foo == bar); // false

System.out.println(foo.equals(bar)); // false

But this is, of course, implementation dependent.

You could make your lambda Serializable and key your callback map with the serlialized representation. See How to serialize a lambda?. While this will work, it's not exactly required to work by the specs.



Related Topics



Leave a reply



Submit