Most immutable Python objects are hashable, so nohtyP will dedicate space (ob_hash) in every ypObject to cache the hash; this space is ignored for mutable objects.  The immutable constructors and yp_freeze will automatically populate ob_hash.  However, it is impossible to calculate the hashes of immortals with the C compiler, so if ob_hash is -1 at runtime, the hash is calculated then cached for future calls.  Also, -1 will be used if the object does not support hashing; the hash calculation function will then be able to return the appropriate error.

So far so good, but some digging into Python shows that using hash() to indicate immutability has some problems:

  • “x in otherset” requires the hash of x in order to find it in otherset.  Because Python doesn’t allow a hash to be calculated if x is mutable, a frozenset copy of x is created and destroyed behind the scenes.  If x is large, this is quite inefficient!
  • The documentation states that user-defined classes are hashable by default, as a convenience to programmers.  However, unless a custom class remembers to set __hash__ to None, they will have a hash value, even if they are mutable.

Really, the hash has more to do with the value of the object than its mutability.  The requirement of immutability only comes into play when storing objects in sets/dicts, as the hash is cached in the hash table to improve lookup speed.  It should be possible to compute the current hash, based on the current value, in contexts where the object is not being stored.  To this end, nohtyP will have a yp_currenthashC function, applicable for immutable objects.

The test for mutability will instead use the type code.  Recall that types will come in mutable/immutable pairs, so the least-significant bit of the type code will indicate if the type is mutable or not.