18

The Groovy "in" operator seems to mean different things in different cases. Sometimes x in y means y.contains(x) and sometimes it seems to call y.isCase(x).

How does Groovy know which one to call? Is there a particular class or set of classes that Groovy knows about which use the .contains method? Or is the behavior triggered by the existence of a method on one of the objects? Are there any cases where the in operator gets changed into something else entirely?

Dónal
  • 185,044
  • 174
  • 569
  • 824
ataylor
  • 64,891
  • 24
  • 161
  • 189

3 Answers3

18

I did some experimentation and it looks like the in operator is based on the isCase method only as demonstrated by the following code

class MyList extends ArrayList {
    boolean isCase(Object val) {
        return val == 66
    }
}

def myList = new MyList()
myList << 55
55 in myList // Returns false but myList.contains(55) returns true     
66 in myList // Returns true but myList.contains(66) returns false

For the JDK collection classes I guess it just seems like the in operator is based on contains() because isCase() calls contains() for those classes.

Rotem
  • 1,381
  • 1
  • 11
  • 23
Dónal
  • 185,044
  • 174
  • 569
  • 824
  • 1
    Ok, that makes sense. I was confused about the relationship between "in" and isCase. I can see now contains makes sense when using a container as a case label. Reusing isCase for the in operator is a little surprising though, since it allows for unexpected expressions like 'asdf' in String == true. – ataylor Jan 15 '10 at 00:05
  • This is correct, but imo poor on the part of groovy. While case statement behaviour and containing an element use the same logic with collections, they are very different in other situations. For example, the following assertion does not pass: assert 'b' in 'buns'. This is counterintuitive to say the least. – Sean Reilly Apr 20 '11 at 13:41
  • can anyone please tell me in short what isCase means? – Amanuel Nega Nov 04 '14 at 12:52
  • `isCase` is a method that Groovy adds to `java.lang.Object` http://groovy-lang.org/docs/latest/html/groovy-jdk/java/lang/Object.html#isCase(java.lang.Object) – Dónal Nov 04 '14 at 15:12
4

It's actually all based on isCase. Groovy adds an isCase method to Collections that is based on the contains method. Any class with isCase can be used with in.

Eel Lee
  • 3,513
  • 2
  • 31
  • 49
noah
  • 21,289
  • 17
  • 64
  • 88
4

in is the "Membership operator".

From the documentation for Groovy 3 (emphasis mine):

8.6. Membership operator

The membership operator (in) is equivalent to calling the isCase method. In the context of a List, it is equivalent to calling contains, like in the following example:

def list = ['Grace','Rob','Emmy']
assert ('Emmy' in list)           # (1)    

(1) equivalent to calling list.contains('Emmy') or list.isCase('Emmy')

So, Groovy always calls isCase, which in case of a List maps to contains.

ciis0
  • 311
  • 1
  • 9