Bug 539589 - Different behaviour when generating hashCode and equals
Summary: Different behaviour when generating hashCode and equals
Status: RESOLVED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 4.9   Edit
Hardware: PC All
: P3 normal (vote)
Target Milestone: 4.10 M1   Edit
Assignee: Pierre-Yves Bigourdan CLA
QA Contact: Till Brychcy CLA
URL:
Whiteboard:
Keywords:
: 540890 (view as bug list)
Depends on:
Blocks:
 
Reported: 2018-09-27 15:28 EDT by Lars Briem CLA
Modified: 2018-11-07 12:34 EST (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Lars Briem CLA 2018-09-27 15:28:16 EDT
Generating hashCode and equals with the new feature "Use Objects.hash and Objects.equals method" considers super.equals, but not super.hashCode. When using the old style, super.hashCode will be considered.

Current generated hashCode method:
public int hashCode() {
    return Objects.hash(variable1, ...)
}

Suggested hashCode method:
public int hashCode() {
    return Objects.hash(super.hashCode(), variable1, ...)
}
Comment 1 Till Brychcy CLA 2018-09-27 16:07:42 EDT
@Pierre-Yves, can you please take care of this?
Comment 2 Till Brychcy CLA 2018-09-27 16:14:56 EDT
Of course this should only be done if necessary ( check GenerateHashCodeEqualsOperation.needsNoSuperCall as for the old code)

But maybe it should better be
    return 31 * super.hashCode() + Objects.hash(variable1, ...) 
to avoid autoboxing of the super.hashCode() result
Comment 3 Pierre-Yves Bigourdan CLA 2018-09-27 17:38:37 EDT
Sure, I'll look into it. Thanks for reporting the issue @Lars!
Comment 4 Pierre-Yves Bigourdan CLA 2018-10-01 17:45:45 EDT
I've spotted another issue when inner classes are used.

Having several "if (!fUseJ7HashEquals) body.statements().add(...)" in the implementation is confusing and is partly what put us in trouble with these two bugs.

I'll strengthen the test suite, perform some refactoring and fix these issues.
Comment 5 Pierre-Yves Bigourdan CLA 2018-10-02 14:35:54 EDT
(In reply to Till Brychcy from comment #2)
> But maybe it should better be
>     return 31 * super.hashCode() + Objects.hash(variable1, ...) 
> to avoid autoboxing of the super.hashCode() result

Wondering some more about this comment. For primitive types, we currently have autoboxing behaviour with the hashCode implementation, i.e. Objects.hash(aBool, aByte, aChar, anInt, aFloat). Is this something we want to address? 

I've come up with two implementation variants, one which simply fixes the issues we've picked up so far in this bug report (super call and inner class), the other one with slightly cleaner refactoring which also happens to address autoboxing for fields.

I'm in two minds here. Even though Objects.hash(aBool, aByte, aChar, anInt, aFloat) causes autoboxing, it seems significantly more succinct than what a non autoboxing implementation would generate:
final int prime = 31;
int result = 1;
result = prime * result + (aBool ? 1231 : 1237);
result = prime * result + aByte;
result = prime * result + aChar;
result = prime * result + anInt;
result = prime * result + Float.floatToIntBits(aFloat);
return result;

What do you think?
Comment 6 Lars Briem CLA 2018-10-04 13:49:34 EDT
Autoboxing is a concern, but readability is much better with one single Objects.hash. If there are performance issues with the autoboxed variant, one could always switch back to the old style.

Taking a look at the future of java, autoboxing may not be an issue anymore after implementing value types/JEP 169 (http://openjdk.java.net/jeps/169).
Comment 7 Till Brychcy CLA 2018-10-04 14:30:34 EDT
(In reply to Lars Briem from comment #6)
> Autoboxing is a concern, but readability is much better with one single
> Objects.hash. If there are performance issues with the autoboxed variant,
> one could always switch back to the old style.
I agree.
Only I wonder if it even looks better to have the super.hashCode() inside the Object.hashCode(...) invocation. I think not, so I'd go for the version without auto boxing just for this case, not for the fields.
But I don't have a strong opinion.

> 
> Taking a look at the future of java, autoboxing may not be an issue anymore
> after implementing value types/JEP 169 (http://openjdk.java.net/jeps/169).
I doubt JEP 169 will help in situations like here (where a method expects an Object array of mixed types)
Comment 8 Till Brychcy CLA 2018-10-04 14:31:31 EDT
@Noopur, adding you to CC in case you have an opinion on the topic
Comment 9 Eclipse Genie CLA 2018-10-06 04:23:51 EDT
New Gerrit change created: https://git.eclipse.org/r/130529
Comment 11 Till Brychcy CLA 2018-10-07 12:21:59 EDT
(In reply to Eclipse Genie from comment #9)
> New Gerrit change created: https://git.eclipse.org/r/130529

Thanks!

During testing I noted two things that could be improved (also in the old implementation, so not related to this bug), for which we could open separate bugs:

- There is a check whether the super class has equals and hashcode implemented. I think the same should be done for the enclosing instance.

- If there are no fields, but an enclosing instance and/or a superclass, hashcode and equals generation is currently disallowed. I think it should be allowed.

(In reply to Eclipse Genie from comment #10)
> Gerrit change https://git.eclipse.org/r/130529 was merged to [master].
> Commit:
> http://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/commit/
> ?id=bbe552787fd049eb492c05ec98276ed5b528a768

Released for 4.10M1
Comment 12 Pierre-Yves Bigourdan CLA 2018-10-07 17:15:33 EDT
Thanks for reviewing!

I'm definitely happy to raise some improvement bugs and have a go at tackling them. I agree with both your observations.
Comment 13 Till Brychcy CLA 2018-11-07 12:34:46 EST
*** Bug 540890 has been marked as a duplicate of this bug. ***