Stefan Urbansky
Stefan Urbansky

Reputation: 148

Primitive types and IN operator

I use the in operator in groovy very much. But now I found an odd behavior.
See the following script.

int x = 1
long y = 1

println "x == y           " + (x == y)           // true
println "x == new Long(y) " + (x == new Long(y)) // true
println "x in [y]         " + (x in [y])         // false Why?
println "[y].contains(x)  " + [y].contains(x)    // false Why?

The in operator or the contains() return false, although the two numbers are equal. But why?

I've learned that a collection can't contain primitive types, but x == new Long(y) is true.

Upvotes: 1

Views: 69

Answers (1)

dsharew
dsharew

Reputation: 10665

Why it is not working?
Because x is int and y is long.

Why (x == y) returns true?
The == operator uses type casting behind so (x == y) is same as:

(x == (int)y)

When you create a list in groovy using [] syntax groovy uses the ArrayList class behind. So the in and contains() method returns depend on the contains() method implementaion:

public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

As you can see it calls indexOf method:

 public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

and the indexOf method actually depends on the equals method implementation of the object passed.

So when you say [y].contains(x) or x in [y] it will use Integer's equals() method implementation:

public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

As you can see it will return false if you are not passing an int regardless of the actual value.

if say [x].contains(y) or y in [x] it will use Long's equals method implementation:

public boolean equals(Object obj) {
        if (obj instanceof Long) {
            return value == ((Long)obj).longValue();
        }
        return false;
    }

which again returns false if the argument is not instance of long regardless of the value.

As further example this code should return false:

int x = 1
long y = 1

x.equals(y)

Upvotes: 3

Related Questions