Part of the difficulty I'm finding with designing JSR-310 (Dates and Times) is that I constantly come across gaps in the language of Java. My concern is that these gaps will shape the API to be less than it should be. Let me give some examples:
BigDecimal
JSR-310 is considering adding classes representing durations. (So is JSR-275, but thats another story.)
The aim of the duration classes is to meet the use case of representing "6 days", or "7 minutes".
As a result, the first set of code uses int to represent the amount.
public class Days { // code is for blog purposes only!
private int amount;
...
}
However, what happens when you get down to seconds and milliseconds? Do we have one class that represents seconds, and a separate class that represents milliseconds? That seems rather naff. What would be better is to have a class to represent seconds with decimal places:
public class Days {
private double amount;
...
}
But double is a no-no.
Like float, it is unreliable - unable to represent some decimal values, and with
sometimes unexpected answers from the maths.
Of course, the answer is BigDecimal:
public class Days {
private BigDecimal amount;
}
So, why am I, and others, reticent to use this 'correct' solution? Its because we don't have BigDecimal literals and operators. This is a clear case where language-level choices are affecting library-level design for the worse.
Immutables
JSR-310 is based around immutable classes, which are now a well recognised best practice for classes like dates and times. Unfortunately, the Java language is not well setup for immutable classes.
Ideally, there should be language level support for immutable classes. This would involve a single keyword to declare a class as immutable, and could allow certain runtime optimisations (so I'm told...).
public immutable class DateTime {
...
}
Unfortunately, it is probably too late for Java to do much on this one.
Self types
Another missing Java feature affecting JSR-310 is self-types. These are where a superclass can declare a method that automatically causes all subclasses to return the same type as the subclass:
public abstract class AbstractDateTime {
public <this> plusYears(Duration duration) {
return factory.create(this.amount + duration); // pseudo-code
}
}
public final class DateTime extends AbstractDateTime {
}
// usage
DateTime result = dateTime.plus(duration);
The thing to note is the 'this' generic style syntax.
The effect is that the user of the subclass was able to use the method and get the correct return type.
They were returned a DateTime rather than a AbstractDateTime.
This can be achieved today by manually overriding the method in each and every subclass. However that doesn't work if you want to add a new method to the abstract superclass in the future and have it picked up by every subclass (which is what you want in a JSR, as a JSR doesn't have a perfect crystal ball for its first release).
Again, a language-level missing feature severely compromises a library-level JSR.
Operator overloading
Another area where JSR-310 may choose the 'wrong' approach is int-wrapper classes. For JSR-310 this would be a class representing a duration in years.
If I were to give you a problem description that said you need to model 'the number of apples' in a shop', and to be able to add, subtract and multiply that number, you'd have a couple of design options.
The first option is to hold an int and perform regular maths using +, - and *.
The downside is that only javadoc tells you that the int is a number of apples,
instead of a number of oranges. This is exactly the situation before generics.
The second option is to create an Apples class wrapping the int.
Now, you cannot confuse apples with oranges.
Unfortunately, you also cannot use +, - and *.
This is despite the fact that they are obviously valid in this scenario.
Using plus/minus/multipliedBy/dividedBy methods just doesn't have the same clarity.
Given this choice today, most architects/designers seem to be choosing the first option of just using an int. Language designers should really be looking at that decision and shaking their head. The whole point of the generics change was to move away from reliance on javadoc. Yet here, in another design corner, people still prefer a lack of real safety and javadoc to 'doing the right thing'. Why? Primarily because of the lack of operator overloading.
Ironically, I think this is an area that really might change in the future. But if JSR-310 has chosen to use int rather than proper classes by that point, a great opportunity will have passed.
Summary
My assertion that language-level features (or rather missing features) affect library design isn't really news. The interesting thing with JSR-310 is just how constraining the missing features are proving to be.
The trouble is that with no clear idea on where the future of the Java language lies, a JSR like 310 cannot make good choices which will fit well with future language change. The danger is that we simply create another date and time library that doesn't fit well with the Java language of 2010 or later.
Opinions welcome on whether JSR-310 should completely ignore potential language changes, or try to make a best guess for the future.