Yesterdays adesso night session on Xtend was really great. There were a lot of questions and interesting discussions. I really enjoyed it.
In preparation for the talk I implemented an example for extension methods and operator overloading based on the joda-time library.
Joda-time is very good for acting with dates and JSR-310 (which will be part of Java 8) is inspired by joda-time. Even though working with joda-time is easy and the code's readability is quite good using Xtend's extension methods and operator overloading makes it even easier to read.
Here are some selected examples from the nightsession. The Xtend class and the tests are available here (https://github.com/xtnh/jodatime-xtend).
The following example is very easy: start at 2012-12-01 and "travel" to 2015-04-30.
In Java one would implement it this way:
package xtnh.xtend.jodatime;
import junit.framework.Assert;
import org.joda.time.DateMidnight;
import org.junit.Test;
public class TimeTravel {
@Test
public void testTimeTravel() {
DateMidnight start = new DateMidnight("2012-12-01");
DateMidnight expected = new DateMidnight("2015-04-30");
DateMidnight end = start.plusYears(2).plusMonths(5).minusDays(1);
Assert.assertTrue(end.isEqual(expected));
}
}
In Xtend it's a little bit shorter, but not as short as it is with extension methods.
package xtnh.xtend.jodatime
import junit.framework.Assert
import org.joda.time.DateMidnight
import org.junit.Test
class TimeTravelXtend {
@Test
def void testTimeTravel() {
val start = new DateMidnight("2012-12-01")
val expected = new DateMidnight("2015-04-30")
val end = start.plusYears(2).plusMonths(5).minusDays(1)
Assert::assertTrue(end.isEqual(expected))
}
}
The next step is to define extension methods that create
ReadablePeriod-object (Days, Months, Years) for a given integer.package xtnh.xtend.jodatime
import org.joda.time.Days
import org.joda.time.Months
import org.joda.time.Years
/**
* Extension library for DateMidnight.
*/
class DateMidnightExtensions {
def static Days days(int days) {
Days::days(days)
}
def static Months months(int months) {
Months::months(months)
}
def static Years years(int years) {
Years::years(years)
}
}
Our example is now more readable, because one can read it "from left to right" like in a real language: "start plus 2 years plus 5 months minus 1 day".
package xtnh.xtend.jodatime
import junit.framework.Assert
import org.joda.time.DateMidnight
import org.junit.Test
import static extension xtnh.xtend.jodatime.DateMidnightExtensions.*
class TimeTravelXtend {
@Test
def void testTimeTravel() {
val start = new DateMidnight("2012-12-01")
val expected = new DateMidnight("2015-04-30")
val end = start.plus(2.years).plus(5.months).minus(1.days)
Assert::assertTrue(end.isEqual(expected))
}
}
If we now overload the plus operator and the minus operator for DateMidnight ...
def static operator_plus(DateMidnight date, ReadablePeriod period) {
date.plus(period)
}
def static operator_minus(DateMidnight date, ReadablePeriod period) {
date.minus(period)
}
... the code is more concise.
package xtnh.xtend.jodatime
import junit.framework.Assert
import org.joda.time.DateMidnight
import org.junit.Test
import static extension xtnh.xtend.jodatime.DateMidnightExtensions.*
class TimeTravelXtend {
@Test
def void testTimeTravel() {
val start = new DateMidnight("2012-12-01")
val expected = new DateMidnight("2015-04-30")
val end = start + 2.years + 5.months - 1.days
Assert::assertTrue(end.isEqual(expected))
}
}
This example shows how easy it is to write readable, short and concise code with Xtend.
For more infos on extension methods and operator overloading you might consult the Xtend documentation.