Equality checks fail in weird ways when using multiple embedded Ruby interpreters

I am embedding multiple Ruby interpreters in a single Java program
(using the newer preferred embedding mechanism “Red Bridge”, although
I doubt that matters for this problem). I am using a single Java
HashMap to communicate state between the different interpreters, I’ll
call this the GlobalVariableStorage. Don’t ask why I’m doing all this
– I am probably using JRuby in ways that was never intended, but I am
sure I want to be doing it :slight_smile:

Anyway, here’s the situation. Interpreter1 puts a nil object in the
GlobalVariableStorage, then interpreter2 pulls the nil object out of
there and compares it to nil like this:
nil_from_global_storage == nil
And this always returns false! Both are instances of NilClass. The
workaround is to do something like:
nil_from_global_store.nil?

But the problem goes deeper than that. Symbol equality fails too. So
if I put :some_symbol in the GlobalVariableStorage, and pull it out in
a different interpreter and do this:
some_symbol_from_global_storage == :some_symbol
That will always be false too. The workaround I came up with in this
case is to convert everything to a String (I guess because it calls
Java’s String.equal() method?).

I think I understand why this is happening. My theory is that Ruby
assumes there is only one instance of NilClass (because it typically
is a singleton) and one instance of every distinct symbol. So for
efficiency it probably just does an object equality check when you
call the == method. This seems perfectly reasonable, so I can’t even
really claim that the behavior I described is a bug.

But I’m curious what the JRuby developers think about this situation?
Write it off as an unsupported use case and I’ll stick to my
workarounds? Or do you think that two different instances of NilClass
should always be considered equal and this could be improved? What
about the situation with symbols?

I hope my description is clear enough. I can put together some example
code if needed.

Adam

At present, it boils down to the fact that all Ruby objects (including
nil) are tied to their runtime, so when you compare them on the Java
side, they’re two different objects.

It’s sort of analogous to how you can create two classloaders in Java,
load the same class in each, create instances of the class from the
two classloaders, and comparison of those two objects will fail even
though they came from the same class file.

This situation is unlikely to change unless and until we do work to
make Ruby objects “exportable” or not tied to the runtime in which
they were created.

Hope that makes sense.

/Nick

Yeah it makes sense, especially for symbols.

Something about the nil comparison failure seems weird though. I feel
like comparing nil to nil should always be true… I wonder if it
could be fixed by having NilClass#==() method return true if the
argument “is_a? NilClass” instead of comparing the objects for
equality? However, if such a change were to make JRuby implementation
diverge from MRI, I understand why you would not want to change it.

In any case, this is something I will just have to be aware of, and
there are reasonable workarounds as I mentioned in my original post.

Adam