torpedro
torpedro

Reputation: 504

List.contains for long values doesn't return expected value (groovy)

I've been playing around with Groovy and ran into this interesting thing. Checking whether a list of longs contains a particular number works when checking integer values, but not when checking long values.

​List<Long> list = [5, 7, 3]

println (5 in list) // true
println (5L in list) // false

int i = 5
long l = 5
println (i in list) // true
println (l in list) // false

Integer i2 = 5
Long l2 = 5
println (i2 in list) // true
println (l2 in list) // false

I ran this code on https://groovyconsole.appspot.com/. This seems broken to me (or at least highly counter-intuitive). I'd expect there to be some issues within the implementation of List.contains and what comparison operator it is using? I can work around that, but I'm wondering if there is something that I'm missing or if that is actually intended behavior?

Upvotes: 4

Views: 1956

Answers (2)

Igor Mukhin
Igor Mukhin

Reputation: 15368

The problem is that you initialize the list with integers. Simply initialize your list with long values:

List<Long> list = [5L, 7L, 3L]

Now you will get what you expect.

Upvotes: 0

jalopaba
jalopaba

Reputation: 8119

This is because type erasure, i.e., no type information at runtime. Since groovy is a dynamic language (dynamic dispatch for methods calls with Meta-Object Protocol, etc.), there is no type checking/static compilation by default.

So your groovy code is roughly equivalent to this groovy code:

def list = [5, 7, 3]
// no type checking by default, so generics types does not matter due to type erasure
[...]

or this pre-generics java code:

   List list = new ArrayList();
   list.add(5);
   list.add(7);
   list.add(3);

   System.out.println(list.contains(5)); // true
   System.out.println(list.contains(5L)); // false
   [...]

If you compile that in java (better with -Xlint) you get the classic Unchecked Error Messages.

From groovy 2.0, you can turn on type checking/static compilation with @groovy.transform.TypeChecked / @groovy.transform.CompileStatic (static compilation triggers also type checking):

@groovy.transform.CompileStatic
class Test {
    static main(args) {
        List<Long> list = [5, 7, 3]

        println (5 in list) // true
        println (5L in list) // false

        int i = 5
        long l = 5
        println (i in list) // true
        println (l in list) // false

        Integer i2 = 5
        Long l2 = new Long(5)
        println (i2 in list) // true
        println (l2 in list) // false        
    }
}

So that you get a compilation error:

[Static type checking] - Incompatible generic argument types. Cannot assign java.util.List <java.lang.Integer> to: java.util.List <Long>

Upvotes: 2

Related Questions