Issue #16850 has been updated by jeremyevans0 (Jeremy Evans). Dan0042 (Daniel DeLorme) wrote in #note-4: > Would it be feasible to raise some sort of error when trying to redefine Integer#hash ? > Not just for this case, but I feel there were other cases where ruby bypasses the method call to use the built-in implementation directly. Can't recall exactly atm. > Making certain methods un-overridable could be a useful signal that "this is not going to work as you expect". It's probably feasible, but I don't think it is a good idea. You can do it in pure Ruby if you want: ```ruby module HashOverrideRaise def method_added(method) raise "don't override hash" if method == :hash super end def include(*) super raise "don't override hash" unless instance_method(:hash).owner == Kernel end end Integer.extend HashOverrideRaise ``` However, this doesn't handle the case in Ana's example, because you are defining Object#hash, and not Integer#hash. The cases where Ruby bypasses method calls to use built-in code are different than this case. Ruby will default to use the faster built-in code, but if you define a method, Ruby will recognize it and start calling the method. This approach is usually referred to as deoptimization. In this case, I don't think it makes sense to change Ruby's behavior. There is no reason to override #hash for the cases where Ruby uses a built-in implementation. So the fact that Ruby does not call #hash in all cases should not be a problem. If you override #eql?, Ruby will still respect that and treat objects differently: ```ruby h = {} s = '' def s.eql?(_) false end h[s] = 1 h[s] = 2 h # => {""=>1, ""=>2} ``` ---------------------------------------- Bug #16850: Object#hash doesn't behave as documented https://bugs.ruby-lang.org/issues/16850#change-85546 * Author: ana06 (Ana Maria Martinez Gomez) * Status: Closed * Priority: Normal * ruby -v: master * Backport: 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN ---------------------------------------- From [Ruby 2.7 Object class documentation](https://ruby-doc.org/core-2.7.0/Object.html#method-i-hash): >The hash value is used along with eql? by the Hash class to determine if two objects reference the same hash key. From this I expect that overwritting the `Object#hash` method changes the Hashing algorithm. But this is only the case for some objets. Consider the following code: ```Ruby class Object def hash i_dont_exist end end class Ana end hash = {} hash[3] = true hash[3] = false puts 'Integers are not using the new hash method' hash[Ana.new] = true puts 'this will not be executed because the class Ana uses the new hash method' ``` The output of executing this code is: ``` Integers are not using the new hash method Traceback (most recent call last): 1: from a.rb:13:in `<main>' a.rb:3:in `hash': undefined local variable or method `i_dont_exist' for #<Ana:0x000055626f0b7a30> (NameError) ``` This proves that Integer hash method is not used to determine if two objects reference the same hash key, as said in the documentation. Check the [`any_hash` method](https://github.com/ruby/ruby/blob/master/hash.c#L188) for the other classes affected. I think that either the behavior should be modified (aiming for a consistency along different classes and following the documentation) or the documentation updated. -- https://bugs.ruby-lang.org/ Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe> <http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>