Wednesday, 23 November 2005

Adding auto casts to Java

OK, so after auto null checks and code blocks what else would make Java that little bit clearer to read and write? What about casts?

Once again, here is an example use case:

public int getAge(Object obj) {
  if (obj instanceof Person) {
    return ((Person) obj).getAge();
  }
  return -1;
}

Note, I've deliberately kept the use case 'stupid'. There are many good OO solutions to this kind of problem, but I believe that the vast majority of Java developers still end up writing nasty casts all the time.

So, what do I propose could be changed in Java 1.6?

public int getAge(Object obj) {
  if (obj instanceof Person) {
    return obj.getAge();
  }
  return -1;
}

The compiler can easily figure out that obj must be an instance of Person in the if statement. So why do we need the cast? The code without the cast is more readable and just as safe.

I still believe that casts have a useful role to play in Java, when you want to emphasise a point in conversion, or to cast without an instanceof. But when we've already checked with the instanceof, why are we have to repeat ourselves? Thats just boilerplate code.

Opinions welcome, as always.

Tuesday, 22 November 2005

Adding auto null checks to Java

So, after considering code blocks yesterday, what about another bane of Java life, nulls. How could they be simplified in a Java-friendly style?

Here's the use case I'm trying to solve:

public isFromBritain(Profile profile) {
  if (profile != null) {
    Person person = profile.getPerson();
    if (person != null) {
      Address address = person.getAddress();
      if (address != null) {
        return "GB".equals(getCountry());
      }
    }
  }
  return false;
}

And here is my proposed solution for JDK1.6:

public isFromBritain(Profile profile) {
  return profile#getPerson()#getAddress()#getCountry()#equals("GB");
}

A bit surprising at first glance, yet much much simpler to read and understand. I'm using # to indicate "ignore null for now and continue processing". I used # as javadoc already uses it instead of a dot. Implementation-wise, the compiler would expand it to the former use-case, so no big issues there.

By the way, this series of entries is inspired by Graham Hamilton's blog about boilerplate Java code. I'm just trying to show what gets in my way, and provide a Java-style (not Ruby/c#/python/... style) solution. As always, opinions welcome :-)

Monday, 21 November 2005

Adding closures to Java, or not...

There has been a lot of talk on Javalobby recently about adding closures to Java. But how can this be done without destroying the style of Java?

Groovy shows one way to add closures. But groovy has the ability to create syntax, change classes and do other strange stuff that is just too way out for Java itself. So I though I'd do an experiment to see if I could figure out a way to add closures to Java following a more java style.

I started with a use case I wanted to solve, the dreaded resource close:

InputStream in = null;
try {
  in = new FileInputStream(file);
  in.read();
  ...
} finally {
  if (in != null) {
    try (
      in.close();
    } catch (IOException ex) {
    }
  }
}

I then played around with some ideas.

My preferred solution was:

do.CloseAfter (InputStream in) {
  in = new FileInputStream(file);
  in.read();
  ...
}

I saw the main benefits as being more readable, shorter, removing the common close code, scoping the variable and reducing errors. Importantly, a current Java programmer would grok the new way of woring very quickly (no complex syntax).

The key was using the do keyword to identify the special code. I believe that this keyword-usage is much more Java-style than arbitrary symbols like ->.

CloseAfter would just be a regular Java class, just limited to have one method:

public class CloseAfter implements ClosureManager {
  public void execute(InputStream in) {
    try {
      call(in);
    } finally {
      if (in != null) {
        try (
          in.close();
        } catch (IOException ex) {
        }
      }
    }
  }
}

For this common case, it would be a JDK class.

Once I'd done all this and convinced myself that the compiler could implement it easily (by copying the CloseAfter code directly into the original method) I had a sudden realisation - this wasn't really closures, but surrounded code blocks.

Nevertheless, it could be very, very useful, for example to do commit and rollback...

do.DBTransaction (Connection con) {
  ...
}

Kind of like AOP-lite :-)

I just have this sense that a syntax like this would be easy to add to Java, and solve 80% of the issues that full-blown closures tackle (with 20% of the complexity). Opinions welcome :-)

Tuesday, 11 October 2005

Commons IO 1.1 done and dusted

Yay! I've successfully navigated the long drawn out process of releasing code from Apache, and Commons-IO 1.1 is now available for download.

(For those of you wondering, Apache demands way more security checks and file updating than a sourceforge release. Thats why, I try and avoid being release manager at Jakarta Commons if possible.)

Anyway, enough of my whining... just go and get the new release! It makes coding any kind of simple IO just a whole lot easier!

Sunday, 21 August 2005

Spot the 'deliberate' mistake...

I was coding in commons lang earlier tonight when I found one of my test cases wasn't passing. It took a few minutes to realise my stupid error. So here's the test! Can you spot it too???

public int readToken(char[] chars, int start) {
  int pos = start;
  while (pos < chars.length) {
    if (chars[pos++] == '"') {
      return pos;
    }
  }
  return start++;
}

(By the way, there are lots of possible errors here like NPE and this is a very simplified version of the actual method, however somewhere here is a particular 'weird' error.












Did you find it?
Its the return statement. You might think on glancing at the code that the method would return the value of start plus one. But it doesn't. It returns the value of start, as the ++ occurs after the return statement. Obvious really - yet in a non-obvious way. The fix of course is to do return ++start; ;-).

(Sorry if you got it straight away, but it amused me for a minute or two...)

Thursday, 11 August 2005

Joda-Time 1.1 is released

It took a while, but version 1.1 of Joda-Time, the replacement for JDK Date and Calendar, has been released!

This release does fix a few bugs, however these were mostly relatively minor. It does however include a number of useful new methods and usability enhancements. For example:

  • a new Partial class, allowing any group of datetime fields to be defined. A typical use might be to create a YearMonth object for a credit card
  • new convenience methods for adding periods, such as plusDays(n) or minusHours(n)
  • YearMonthDay and TimeOfDay are now comparable
  • new methods to create a Period from two YearMonthDay or two TimeOfDay objects
  • new methods on Interval - gap, abuts and overlap
  • better handling of two digit years in formatting/parsing
  • added ISO formats for ordinal (dayOfYear) dates

And stay tuned for announcements about Hibernate and JSP integration!

Full details can be found on the website.

Oh, and if anyone wants to help develop another calendar systems, such as Hebrew, Islamic, Chinese, etc. then please contact me!!!

Sunday, 26 June 2005

Compiling for older JDKs

Most developers seem to assume that they can simply set the javac setting to output 1.2 or 1.3 compatible bytecodes, and they can then compile using JDK1.4 or 1.5. But, this doesn't work.

The problem is that the Java class libraries have changed between JDK1,3 and 1.4 (and so on). Each change provides the potential to break the build.

For example, in JDK1.4 a new method was added to StringBuffer - append(StringBuffer). In itself, this was not newsworthy. However, this method overloads (not overrides!) other methods, notably append(Object).

If you compile using JDK1.4, and you are appending a StringBuffer to a StringBUffer, javac will choose the nice JDK1.4 append(StringBuffer) method. When you use this JAR on JDK1.3 however, you will get a NoSuchMethodError (not Exception!). This is because overloaded methods are bound into the bytecode at compile time.

Oh, and that 'use 1.3 bytecodes' flag in javac? Well that makes no difference. It just avoids writing bad bytecodes, and doesn't check for valid methods.

I'm writing this because it has come up twice recently on commons-dev. Firstly, during the release of Jelly 1.0, where it took quite some effort to convince people of the problem. Secondly, during ongoing work on Email 1.0, where exactly this issue occurred.

The only safe solution is to:

  • compile the JAR file using the lowest JDK supported by your open source library
  • make sure that is the JAR file released to ibiblio's maven repository
  • include that jar file in the source distribution as well as the binary
  • make sure that the manifest file correctly references the lowest JDK version
And to achieve this I use ant and not maven.

Its not a maven issue per se, but maven does require a higher JDK to run itself than most of the libraries I release. Now, I am told that maven can build using a different JDK version to that which it runs on (maven.compile.executable). Well, great if that works. But, I'm not sure that I trust it to actually do all the necessary steps.

Hence my appoach - all compilation steps are done with ant. All website steps are done with maven. Just using the right tool for the right problem in my book.