Sunday, August 12, 2012

Groovy Day 1 : Truth (1/2)

This post is the first of the serie on Groovy discovery. To start easily the learning of Groovy, we need to understand the differences with Java. Groovy is a language that is compiled in bytecode like Java. The bytecode is then read by the same JVM. In other words, Groovy can use Java library (all the .jar that you can find in the internet, quite amazing) and Java can use Groovy library too ! The magic of bytecode in some sense. We could also imagine an interaction with Scala or JRuby etc. all the JVM language are intercompatible. This was for introduction, let's discover the first real part. The Groovy Truth is something very weird for an old Java developper. In Java we have some really particular cases to learn and understand to avoid common mistakes.
Examples:
// Language: JAVA
// expected cases
assert 3 == 3 // basic equality
assert 4L == 4 // long integer equals integer version

// equality on reference 1
// A is a class that does not overload the equals method
A a1 = new A(3);
A a2 = new A(3);
assert a1 != a2; // there are two different objects so they are different
assert !a1.equals(a2); // the equals method is not overloaded, so the basic reference is used by the JVM

A a3 = a1; // we put the reference to a1 in a3
assert a1 == a3; // now the reference are the same
assert a1.equals(a3); // same as before the equals is not overloaded so the reference are used

// B is a class that overload equals method, so that the method compares the internal value directly
B b1 = new B(1);
B b2 = new B(2);
B b3 = new B(1);

assert b1 != b2; // the references are still different
assert b1 != b3;
assert !b1.equals(b2); // the equals method is used, so we compare their internal value, '1' with '2'
assert b1.equals(b3); // this is true because '1' == '1' 

// third part: the strings, in Java the string are stored natively in memory 
// and the String object have reference to the intern memory,
// so the equals is quite the same as '=='
String str1 = "hello world";
String str2 = "hello you";
String str3 = "hello world";
String str4 = "hell" + "o world"; // concatenation of strings resulting in the same string value
assert str1 != str2;
assert str1 == str3;
assert str1 == str4;

1 : String equalityAdvance reference
This is what we expect in Java, not necessarily in other languages and that is the problem when we start with Groovy.

Grooy truth:

// Language: GROOVY
// like before
assert 3 == 3
assert 4L = 4

// but in groovy the equals is replace by == and == by "is" operator
// for class that does not implement equals it's quite the same as Java

// class that does not overload equals
A a1 = new A(3)
A a2 = new A(4)

assert a1 != a2 // internally groovy use a1.equals(a2)
assert !a1.is(a2) // the '==' equivalent of Java

// class that overload equals method
B b1 = new B(3)
B b2 = new B(4)
B b3 = new B(3) // same value
B b4 = b1 // same reference

// here the things get more normal for a non-Java developper
assert b1 != b2
assert b1 == b3 // use equals, so compare internally the value
assert b1 == b4 // the reference are the same, so the equals returns true
assert !b1.is(b3)
assert b1.is(b4) // same reference

// the strings come back to normal behavior not like Java with its static memory table to store Strings value
assert "hello world" == "hello world"
assert "hello you" != "hello me"

// ready for weirdest thing in Groovy ?
// Let's go, when a class implements Comparable in Groovy,
// the == is no more the method equals, but now, the compareTo that should return 0 !

// C is a class that implements Comparable and overload equals
// compare method use the first value and the equals method the second
C c1 = new C(3, 5)
C c2 = new C(2, 5)
C c3 = new C(3, 6)

assert c1.equals(c2) // the second values are the same, 5 == 5
assert !c1.equals(c3) // 5 != 6
assert c1 != c2 // compare 3 and 2 => not 0
assert c1 == c3 // compare 3 and 3

If you are not aware of this, we would have lots of bug without knowing the source because it's hidden, so don't forget to be consistant between equals / compareTo
Here is the source code for the A, B, C classes, in groovy:
// Language: GROOVY
class A {
   int val
 
   A(int _val){
      this.val = _val
   }
}

class B {
   int val
 
   B(int _val){
      this.val = _val
   }
   
   @Override
   public boolean equals(Object obj) {
      if(obj instanceof B){
         B that = (C) obj
         if(this.val == that.val){
            return true
         }
      }
      return false
   } 
}

class C implements Comparable<C>{
   int valEqual
   int valComparable
 
   C(int _valComparable, int _valEqual){
      this.valEqual = _valEqual
      this.valComparable = _valComparable
   }
 
   @Override
   public boolean equals(Object obj) {
      if(obj instanceof C){
         C that = (C) obj
         if(this.valEqual == that.valEqual){
            return true
         }
      }
      return false
   }
 
   @Override
   public int compareTo(C that) {
      // <=> is a special groovy operator that replace .compareTo method
      // in this case we use to compare integer with the normal compareTo method
      return this.valComparable <=> that.valComparable
   }
}
Hope that will help you avoiding errors and understand the real Groovy Truth !

No comments:

Post a Comment