What is the meaning of double tilde (~~) in Java?

JavaGwtBit ManipulationBitwise Operators

Java Problem Overview


When browsing the source code of Guava, I came across the following piece of code (part of the implementation of hashCode for the inner class CartesianSet):

int adjust = size() - 1;
for (int i = 0; i < axes.size(); i++) {
    adjust *= 31;
    adjust = ~~adjust;
    // in GWT, we have to deal with integer overflow carefully
}
int hash = 1;
for (Set<E> axis : axes) {
    hash = 31 * hash + (size() / axis.size() * axis.hashCode());

    hash = ~~hash;
}
hash += adjust;
return ~~hash;

Both of adjust and hash are ints. From what I know about Java, ~ means bitwise negation, so adjust = ~~adjust and hash = ~~hash should leave the variables unchanged. Running the small test (with assertions enabled, of course),

for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
    assert i == ~~i;
}

confirms this. Assuming that the Guava guys know what they are doing, there must be a reason for them to do this. The question is what?

EDIT As pointed out in the comments, the test above doesn't include the case where i equals Integer.MAX_VALUE. Since i <= Integer.MAX_VALUE is always true, we will need to check that case outside the loop to prevent it from looping forever. However, the line

assert Integer.MAX_VALUE == ~~Integer.MAX_VALUE;

yields the compiler warning "Comparing identical expressions", which pretty much nails it.

Java Solutions


Solution 1 - Java

In Java, it means nothing.

But that comment says that the line is specifically for GWT, which is a way to compile Java to JavaScript.

In JavaScript, integers are kind of like doubles-that-act-as-integers. They have a max value of 2^53, for instance. But bitwise operators treat numbers as if they're 32-bit, which is exactly what you want in this code. In other words, ~~hash says "treat hash as a 32-bit number" in JavaScript. Specifically, it discards all but the bottom 32 bits (since the bitwise ~ operators only looks at the bottom 32 bits), which is identical to how Java's overflow works.

If you didn't have that, the hash code of the object would be different depending on whether it's evaluated in Java-land or in JavaScript land (via a GWT compilation).

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHalle KnastView Question on Stackoverflow
Solution 1 - JavayshavitView Answer on Stackoverflow