Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hashCode() to classes with equals() and clean up equals() #1222

Merged
merged 5 commits into from
Nov 14, 2018

Conversation

jmthibault79
Copy link
Contributor

@jmthibault79 jmthibault79 commented Nov 7, 2018

Description

equals() without hashCode() is bad news. Also, some equals() have problems too.

Checklist

  • Code compiles correctly
  • New tests covering changes and new functionality
  • All tests passing
  • Extended the README / documentation, if necessary
  • Is not backward compatible (breaks binary or source compatibility)

@jmthibault79
Copy link
Contributor Author

jmthibault79 commented Nov 7, 2018

Also, fix 3 classes' equals() Scope expanded to cover more equals()

@@ -65,8 +66,12 @@ public boolean equals(final Object obj) {

final Bases bases = (Bases) obj;

return position == bases.position && !Arrays.equals(this.bases, bases.bases);
return position == bases.position && Arrays.equals(this.bases, bases.bases);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yikes

@@ -64,10 +65,14 @@ public boolean equals(final Object obj) {
if (!(obj instanceof Deletion))
return false;

final Deletion deleteion = (Deletion) obj;
final Deletion other = (Deletion) obj;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spelling

@codecov-io
Copy link

codecov-io commented Nov 7, 2018

Codecov Report

Merging #1222 into master will decrease coverage by 0.04%.
The diff coverage is 6.78%.

@@              Coverage Diff               @@
##              master     #1222      +/-   ##
==============================================
- Coverage     69.016%   68.975%   -0.04%     
- Complexity      8066      8072       +6     
==============================================
  Files            539       539              
  Lines          32552     32587      +35     
  Branches        5488      5510      +22     
==============================================
+ Hits           22466     22477      +11     
- Misses          7890      7903      +13     
- Partials        2196      2207      +11
Impacted Files Coverage Δ Complexity Δ
src/main/java/htsjdk/tribble/index/Block.java 56.25% <0%> (-3.75%) 6 <1> (ø)
...k/samtools/cram/encoding/readfeatures/Padding.java 36.842% <0%> (-2.047%) 4 <0> (ø)
...k/samtools/cram/encoding/readfeatures/RefSkip.java 36.842% <0%> (-2.047%) 4 <0> (ø)
.../samtools/cram/encoding/readfeatures/Deletion.java 36.842% <0%> (-2.047%) 4 <0> (ø)
.../samtools/cram/encoding/readfeatures/ReadBase.java 36% <0%> (-1.5%) 5 <0> (ø)
.../java/htsjdk/tribble/index/linear/LinearIndex.java 77.907% <0%> (-0.456%) 18 <0> (ø)
.../samtools/cram/encoding/readfeatures/HardClip.java 36.842% <0%> (-2.047%) 4 <0> (ø)
...samtools/cram/encoding/readfeatures/Insertion.java 31.818% <0%> (-7.071%) 4 <0> (ø)
...amtools/cram/encoding/readfeatures/InsertBase.java 65% <0%> (-3.421%) 7 <0> (ø)
...huffman/codec/CanonicalHuffmanIntegerEncoding.java 76.923% <0%> (-8.791%) 10 <0> (ø)
... and 12 more

@@ -125,6 +126,15 @@ public boolean equals(final Object obj) {

}

@Override
public int hashCode() {
// Note: flags covers these checks as well:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll probably revisit this when I refactor CramCompressionRecord in earnest

@jmthibault79 jmthibault79 changed the title Add hashCode() to classes with equals() Add hashCode() to classes with equals() and clean up equals() Nov 7, 2018
Copy link
Member

@lbergelson lbergelson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jmthibault79 Thanks for doing this. I think there are still a bunch of problems here due to the annoying fact that Array doesn't override Object.hashCode.


@Override
public int hashCode() {
return Objects.hash(position, bases);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't this use the memory location of bases instead of the base values?


@Override
public int hashCode() {
return Objects.hash(bitLengths, values);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this just uses the default hashcode, not equivalent to Arrays.hashCode().

@@ -52,11 +54,16 @@ public int compareTo(@SuppressWarnings("NullableProblems") final Version o) {
*/
@Override
public boolean equals(final Object obj) {
if (obj == null || !(obj instanceof Version)) return false;
if (obj == null || (obj.getClass() != getClass())) return false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like this isn't consistent with the compareTo method since that takes build into account as well. You don't have to make it so but you should add a comment if you don't.


final Insertion insertion = (Insertion) obj;

return position == insertion.position && Arrays.equals(sequence, insertion.sequence);
}

@Override
public int hashCode() {
return Objects.hash(position, sequence);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same problem with Object.equals vs Arrays.equals.


@Override
public int hashCode() {
return Objects.hash(position, scores);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same issue

// Note: flags covers these checks as well:
// isNegativeStrand(), isVendorFiltered(), isSegmentUnmapped(), isLastSegment(), isFirstSegment()

return Objects.hash(alignmentStart, flags, readLength, recordsToNextFragment, mappingQuality, readFeatures,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same problem with arrays

@@ -103,6 +103,10 @@ public boolean equals(final Object obj) {
return Arrays.equals(id, header.id) && getSamFileHeader().equals(header.getSamFileHeader());
}

@Override
public int hashCode() {
return Objects.hash(version, id, samFileHeader);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be aware that if you update version.hashCode to take build into account that now this will no longer be correct since this doesn't compare with version.equals.

@@ -154,17 +155,15 @@ public int compareTo(@SuppressWarnings("NullableProblems") final ReadTag o) {

@Override
public boolean equals(final Object obj) {
if (!(obj instanceof ReadTag))
return false;
if (obj == null || (obj.getClass() != getClass())) return false;

final ReadTag foe = (ReadTag) obj;
return key.equals(foe.key) && (value == null && foe.value == null || value != null && value.equals(foe.value));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This definition and it's hashCode are correctly matching now. There's a problem with the equals method for cases of 'H' and 'B'. 'H' returns an array which should be compared using Arrays.equals() , and 'B' returns a TagValueAndUnsignedArrayFlag which doesn't implement equals.

Fixing the array case will require a corresponding change to the hashCode.

@@ -135,6 +132,11 @@ public boolean equals(Object other) {
return true;
}

@Override
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this really has to hash every element of sequenceEntries.

@@ -116,6 +116,11 @@ public boolean equals(final Object obj) {
return true;
}

@Override
public int hashCode() {
return Objects.hash(position, code, referenceBase, base);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this has to be clever about the case where code = NO_CODE and ignore referenceBase and base in that case.


public class CanonicalHuffmanIntegerEncoding implements Encoding<Integer> {
private static final EncodingID ENCODING_ID = EncodingID.HUFFMAN;
private int[] bitLengths;
private int[] values;
private final ByteBuffer buf = ByteBuffer.allocate(1024 * 10);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved inside method where it belongs, and it shouldn't be used for equality tests

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you want to localize this to the method it's used in, because that means re-allocating it every time. That seems like it could be a substantial performance hit through increased garbage collection.

You can just ignore it in equality checks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point - I'll fix that in the general Encoding refactor as well

Copy link
Member

@lbergelson lbergelson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jmthibault79 Looks good except for moving that buffer out of the field.

@lbergelson lbergelson assigned jmthibault79 and unassigned lbergelson and cmnbroad Nov 9, 2018
@jmthibault79
Copy link
Contributor Author

Restored buf @lbergelson

Copy link
Member

@lbergelson lbergelson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants