-
-
Notifications
You must be signed in to change notification settings - Fork 942
Description
Environment
- jruby 9.2.8.0 (2.5.3) 2019-08-12 a1ac7ff OpenJDK 64-Bit Server VM 11.0.5+10 on 11.0.5+10 +jit [darwin-x86_64]
Expected Behavior
The following RSpec should pass:
describe Java::OrgJodaTime::LocalDate do
it 'correctly implements reference equality' do
a = Java::OrgJodaTime::LocalDate.new(2018, 12, 4)
b = Java::OrgJodaTime::LocalDate.new(2018, 12, 4)
expect(a == b).to be_truthy
expect(a.__id__ == b.__id__).to be_falsy
expect(a.equal? a).to be_truthy
expect(a.equal? b).to be_falsy
end
endActual Behavior
The last expect fails, since a.equal? ends up calling the Java isEqual method on the LocalDate object, which implements value equality.
Per https://ruby-doc.org/core-2.5.3/BasicObject.html#method-i-equal-3F, the equal? method should never be overridden and should always implement object identity comparison. However, some Java classes (notably including any JodaTime classes inheriting from AbstractPartial) may have an isEqual method which implements some other, weaker type of comparison and which JRuby automatically calls when equal? is called on such an object from Ruby.
IMO this is not a bug in JodaTime, since it's a pure Java library that is not designed with either Ruby's conventions or JRuby's idiosyncratic method resolution in mind. Instead, I would consider it a bug in JRuby itself: in attempting to bridge the different method naming conventions in Ruby and Java, it should also respect other established conventions of the two platforms and the "principle of least surprise", e.g. by not overriding equal? for classes whose author did not intend to do so.
This is particularly relevant since JRuby itself ships with JodaTime, which includes classes that trigger this bug.
FWIW, we've worked around this issue in our own codebase with a monkey patch like this:
class Java::OrgJodaTime::LocalDate
def equal?(other)
__id__ == other.__id__
end
endwhich restores the expected behavior. However, this is really only hiding the problem, and in any case only addresses it for one single class.