Re: Hash Surprises with Fixnum, #hash, and #eql?
- From: Clifford Heath <no@xxxxxxxxxxxxxxx>
- Date: Fri, 08 Apr 2011 17:29:30 +1000
On 04/07/11 19:19, Robert Klemme wrote:
On Thu, Apr 7, 2011 at 6:05 AM, Clifford Heath<no@xxxxxxxxxxxxxxx> wrote:I have a class which delegates for Integer, and wants to behave as muchThere's still a lot missing for a number replacement. Please see
like a real Integer as possible (except for being able to be subclassed).
Yes, you wrote that about the time we discussed it last time.
I also doubt whether it is a good idea to allow for subclassing of an
integer like class. What use case do you have in mind which would
make this necessary?
What's wrong with the case you use in that blog post? But as it turns out,
I'm implementing a fact-based modeling DSL, where it's sensible to have
classes like "AgeInYears" being a subclass of an integer like class.
The formalism for this comes directly from sorted first-order logic,
which makes a good deal more sense than the broken O-O paradigm discussed
elsewhere in this thread.
I suspect that you "doubt it is a good idea" only because Ruby's object
model for numbers is inconsistent, and you're defensive about that. Not
because Ruby 2.0 shouldn't move in the direction of fixing it, where
possible. (BTW, I tried to join Ruby Core to discuss this, but all
possible means of subscription are silently failing me).
Note that I'm not actually subclassing any core integer class. I'm just
defining a new base class "Int" which contains an integer, and so far
as is possible, acts like one, including being found in a Hash using a
If Fixnum and Bignum can act like Integer subclasses, why can't my class?
In particular, the Hash implementations work (and break!) differently inWhen you violate contracts you cannot expect code to work properly.
MRI, Rubinius and JRuby. It's documented to use only #hash and #eql?,
but that's not always true (sometimes these have hard-wired optimsations).
I have not violated that (unstated!) contract. Read again; I redefine
Fixnum#eql? as self.orig_eql?(i.to_i) - the to_i makes it symmetrical.
(Debate the wisdom if you wish, it's just for demonstration purposes.)
However the Ruby interpreters do not honor that. In short, *all three*
mentioned Ruby interpreters violate the Hash contract, which states that
hash and eql? are used for Hash lookups. Not just sometimes, but all the
time, including for integers.
MRI uses a Fixnum as its own hash value, even if you've monkey-patched a
hash method into Fixnum. This optimisation should not be always-on. Instead,
Ruby should detect when Fixnum has been patched, and bypass the optimisation.
That would require a single test and branch, with insignificant impact on
performance. MRI does however use a monkey-patched Fixnum#eql? method.
Rubinius does the opposite. It calls a patched Fixnum#hash, but not Fixnum#eql?
JRuby calls neither.
The Ruby interpreters should behave the way the Hash documentation says they do.
The Ruby documentation should explicitly state that eql? must be defined
symmetrically, or should require that the Hash implementation uses it only
in a known direction or both.
The Hash documentation does not say whether #eql? will be called only on
items in the hash, or only on keys being used to probe the hash. It should
be one or the other, since a.eql?(b) might not always mean b.eql?(a).
But that is the contract as far as I can see.
That's not documented anywhere I can see. Certainly not in TRPL, see sections
3.4.2 on page 68, and section 184.108.40.206 page 77. It makes sense, but it's not
results for both violates the equivalence relation which means all
bets are off.
No. I can fix the asymmetry. I can't make the interpreters honor that fix.
You'll see that the behaviour is very unpredictable.Yes, because of your violation of the contract.
No. Because the Ruby interpreters don't honor the Hash contract.
Please try to read more carefully.
- Prev by Date: Re: String.gsub with regex and block
- Next by Date: How do I trap Ctrl-C so it doesn't reach spawned threads?
- Previous by thread: Re: Hash Surprises with Fixnum, #hash, and #eql?
- Next by thread: Re: Hash Surprises with Fixnum, #hash, and #eql?