[IronPython] IronPython.Objects.List doesn't support GetHashCode()

Jim Hugunin jimhug at exchange.microsoft.com
Thu May 12 19:22:10 CEST 2005


SyncRoot should be supported on lists.  This wasn't done only due to laziness on my part.

GetHashCode is less clear.  The property of GetHashCode that you're missing is that it must be consistent with Equals.  This is required by both Python and the CLI.  It's not possible to implement Python's notion of list equality and a correct GetHashCode at the same time.

In Python, the standard design for collections is to make them compare equals based on the values they contain not on the identity of the objects.  Consider the following:

>>> a = []
>>> b = []
>>> a == b
True
>>> a is b
False
>>> a.append(1)
>>> a == b
False
>>> b.append(1)
>>> a == b
True

Lists compare equal when all of their members are equal.  This is very useful behavior.  If you want to test for reference equality, in Python you can always use 'is'.  Because lists are mutable and yet compare equal based on value, the only legal hashcode would be a constant int.  I think that Python wisely makes the design choice to throw in this case rather than turning dictionaries into linked lists.

The standard CLI collections ignore their contents when testing for equality and compare based on reference equality.  Because of this decision, they can default to the generic GetHashCode and Equals implementations.

>>> from System.Collections import *
>>> c = ArrayList()
>>> d = ArrayList()
>>> c == d
False
>>> c.Equals(d)
False

Personally, I think that the Python design rules are more useful for collection types because you can always fall back to using 'is' and an identity hashtable implementation when you want to check for object identity rather than object value.  From what I understand of the purpose of your hashtables, I'd argue that they should clearly be identity based hashtables.  These are quite easy to implement by providing a custom IEqualityComparer<K> to IDictionary<K,V>.  It's about 10 lines of code.

This is an interesting and subtle mismatch between the Python and CLI where I'm not sure what the best final solution is.  I don't know if this is just a difference in philosophy in the design of Python's collections and the CLI collections or if there is a more clear distinction between the contract of GetHashCode and Python's __hash__.  There are different ways to tackle this depending on the answer to that question.  One option is to make GetHashCode and Equals on IronPython.Objects.List return CLI-style object versions, but then to provide two new Python-style methods that would provide the correct semantics from the IronPython side.

Lots to think about - Jim


________________________________________
From: users-ironpython.com-bounces at lists.ironpython.com [mailto:users-ironpython.com-bounces at lists.ironpython.com] On Behalf Of Chris Anderson
Sent: Thursday, May 12, 2005 9:40 AM
To: users-ironpython.com at lists.ironpython.com
Subject: Re: [IronPython] IronPython.Objects.List doesn't support GetHashCode()

The problem with this model is that it requires you to subclass and use a special type. My goal is to enable simple usage in binding scenarios: 
 
_list.ItemsSource = range(5)
 
This means that every list/dictionary/touple needs to support ICustomTypeDescriptor and GetHashCode/SyncRoot... The ICD requirement for object/dict is pretty solid, but I'll follow up with our databinding team to see if we can gracefully support non-hash supporting objects... 
 
I'm unclear as to why returning the default CLR implementation of GetHashCode would be bad? It's unique to the life of the object and never changes... it won't be based on the containing data in the list, but it also shouldn't break any hashtable... no? 


 
On 5/12/05, Timothy Fitz <firemoth at gmail.com> wrote: 
Not directly, but subclassing list and dict would work.

class HashableList:
def __hash__(self):
   return id(self)

or

clash HashableList:
def __hash__(self):
   return 1

To adapt simply:

HashableList(MyExistingList)

Disclaimer, I'm not sure if this works in IronPython today.




More information about the Ironpython-users mailing list