Showing posts with label java7. Show all posts
Showing posts with label java7. Show all posts

Monday, 23 November 2009

More detail on Closures in JDK 7

This blog goes into a little more detail about the closures announcement at Devoxx and subsequent information that has become apparent.

Closures in JDK 7

At Devoxx 2009, Mark Reinhold from Sun announced that it was time for closures in Java. This was a big surprise to everyone, and there was a bit of a vacuum as to what was announced. More information is now available.

Firstly, Sun, via Mark, have chosen to accept the basic case for including closures in Java. By doing so, the debate now changes from whether to go ahead, to how to proceed. This is an important step.

Secondly, what did Mark consider to be in and what out? Well, he indicated that non-local returns and the control-invocation statement were out of scope. There was also some indication that access to non-final variables may be out of scope (this is mainly because it raises nasty multi-threading Java Memory Model issues with local variables).

In terms of what was included, Mark indicated that extension methods would be considered. This would be necessary to provide meaningful closure style APIs since the existing Java collection APIs cannot be altered. The result of what was in was being called "simple closures".

Finally, Mark offered up a possible syntax. The syntax he showed was very close to FCM:

  // function expressions
  #(int i, String s) {
    System.println.out(s);
    return i + str.length();
  }

  // function expressions
  #(int i, String s) (i + str.length())
  
  // function types
  #int(int, String)

As such, its easy to say that Sun has "chosen the FCM proposal". However, with all language changes, we have to look at the semantics, not the syntax!

The other session at Devoxx was the late night BOF session. I didn't attend, however according to Reinier Zwitserloot, Mark indicated that Exception transparancy might not be essential to the final proposal.

According to Reinier, Mark also said "It is not an endorsement of FCM. He was very specific about that." I'd like to consider that in a little more detail (below).

The final twist was when a new proposal by Neal Gafter was launched which I'm referring to as the CFJ proposal. After some initial confusion, it became clear that this was written 2 weeks before Devoxx, and that Neal had discussed it primarily with James Gosling on the basis of it being a "compromise proposal". Neal has also stated that he didn't speak to Mark directly before Devoxx (and nor did I).

There are a number of elements that have come together in the various proposals:

  CICE BGGA 0.5 FCM 0.5 CFJ 0.6a Mark's announcement
(Devoxx summary)
Literals for reflection - - Yes - No
(No info)
Method references - - Yes Yes Worth investigating
(No info)
Closures assignable to
single method interface
Yes Yes Yes Yes Yes
(No info)
Closures independent of
single method interface
- Yes Yes Yes Yes
Access non-final local variables Yes Yes Yes Yes No
(Maybe not)
Keyword 'this' binds to
enclosing class
- Yes Yes Yes No info
(Probably yes)
Local 'return'
(binds to closure)
Yes - Yes Yes Yes
Non-local 'return'
(binds to enclosing method)
- Yes - - No
Alternative 'return' binding
(Last-line-no-semicolon)
- Yes - - No
Exception transparancy - Yes Yes Yes No info
(Maybe not)
Function types - Yes Yes Yes Yes
Library based Control Structure - Yes - - No
Proposed closure syntax Name(args) {block} {args => block;expr} #(args) {block} #(args) {block}
#(args) expr
#(args) {block}
#(args) (expr)

A table never captures the full detail of any proposal. However, I hope that I've demonstrated some key points.

Firstly, the table shows how the CFJ is worthy of a new name (from BGGA) as it treats the problem space differently by avoiding non-local returns and control invocation. Neal Gafter is also the only author of the CFJ proposal, unlike BGGA.

Secondly, it should be clear that at the high level, the CFJ and FCM proposals are similar. But in many respects, this is also a result of what would naturally occur when the non-local returns and control invocation is removed from BGGA.

Finally, it should be clear that it is not certain that the CFJ proposal meets the aims that Mark announced at Devoxx ("simple closures"). There simply isn't enough hard information to make that judgement.

One question I've seen on a few tweets and blog posts is whether Mark and Sun picked the BGGA or FCM proposal. Well, given what Mark said in the BOF (via Reinier), the answer is that neither was "picked" and that he'd like to see a new form of "simple closures" created. However, it should also be clear that the choices announced at Devoxx were certainly closer to the FCM proposal than any other proposal widely circulated at the time of the announcement.

At this point, it is critical to note that Neal Gafter adds a huge amount of technical detail to each proposal he is involved with - both BGGA and CFJ. The FCM proposal, while considerably more detailed than CICE, was never at the level necessary for full usage in the JDK. As such, I welcome the CFJ proposal as taking key points from FCM and applying the rigour from BGGA.

As of now, there has been relatively little debate on extension methods.

Summary

The key point now is to focus on how to implement closures within the overall scope laid out. This should allow the discussion to move forward considerably, and hopefully with less acrimony.

Thursday, 19 November 2009

Closures in JDK 7

So, on Wednesday, Mark Reinhold from Sun announced that it was time for closures in Java. This came as a surprise to everyone, but what was announced?

Closures in JDK 7

Mark took the audience through the new features of JDK 7 in his presentation at Devoxx. As part of this he showed the Fork Join framework.

Part of this framework features a set of interfaces to support functional style predicates and transforms. But, in order to implement this in Java required 80 interfaces, all generified, and that only covered 4 of the primitive types! Basically, Mark, and others, had clearly come to the conclusion that this code was important to Java, but that the implementation with single-method interfaces, generics and inner classes was too horrible to stomach for the JDK.

Thus, 'its time to add closures to Java'.

Mark announced that Sun would investigate, and intended to commit, closures to OpenJDK for JDK 7. While there will be no JSR yet, it isn't unreasonable to expect that there will be an open aspect to discussions.

Mark noted that the work in the closures discussion, and particularly the detail in the BGGA proposal, had allowed the options to be properly explored. He emphasised how this had resulted in the decision to reject key aspects of BGGA.

JDK 7 closures will not have control-invocation statements as a goal, nor will it have non-local returns. He also indicated that access to non-final variables was unlikely. Beyond this, there wasn't much detail on semantics, nor do I believe that there has been much consideration of semantics yet.

On syntax, Mark wrote up some strawman syntaxes. These follow the FCM syntax style:

  // function expressions
  #(int i, String s) {
    System.println.out(s);
    return i + s.length();
  }

  // function expressions
  #(int i, String s) (i + s.length())
  
  // function types
  #int(int, String)

Mark also argued that a form of extension methods would be added to allow closures to be used with existing libraries like the collections API.

Although I must emphasise that everything announced was a proposal and NOT based on any specific proposal (BGGA, FCM or CICE). However, the syntax and semantics do follow the FCM proposal quite closely.

In addition, Neal Gafter has produced an initial formal writeup of what was announced derived from BGGA. Based on my initial reading, I believe that Neal's document represents a good place to start from. I also hereby propose that we refer to Neal's document as the CFJ proposal (Closures for Java), as BGGA rather implies control invocation.

So, lets hope the process for closures provides for feedback, and we get the best closures in the style most suitable for Java in JDK 7.

Thursday, 10 September 2009

JDK 7 - Method suggestions

Joe Darcy has opened up a call for methods to add to the core JDK 7 lang/util package. The idea is to add methods that are "commonly-written utility methods".

JDK 7 utility methods

There is lots of prior art in the field of general utility method libraries for Java. Perhaps the best known is Apache Commons Lang. Lets choose some methods (other than string utilities) that might be appropriate for the JDK from ObjectUtils.

1) Null-safe equals check.
boolean Objects.equals(Object object1, Object object2)
Returns true if both are null, or both are non-null and equal.

2) Null-safe hash code.
int Objects.hashCode(Object object)
Returns the hash code of the object, or zero if the object is null.

3) Null-safe toString.
String Objects.toString(Object object)
Returns the toString of the object, or "" if the object is null.

4) Null-safe toString with specified default.
String Objects.toString(Object object, String defaultStr)
Returns the toString of the object, or defaultStr if the object is null.

5) Null-safe object defaulting.
T Objects.defaultNull(T object, T defaultValue)
Returns the object, or defaultValue if the object is null.
(Of course, the Elvis operator is a much clearer approach for this common case...)

6) Get maximum and minimum.
T Objects.max(T comparable1, T comparable2)
T Objects.min(T comparable1, T comparable2)
Returns the maximum/minimum object, returning the non-null object if either is null, or null if both are null.
Generics allow the return type to check the input is also a Comparable.

These would appear to be the obvious methods to add to an Objects utility class.

The following are missing methods on Integer/Long:

7) Compare two primitives.
int Byte.compare(byte value1, byte value2)
int Short.compare(short value1, short value2)
int Integer.compare(int value1, int value2)
int Long.compare(long value1, long value2)
Safely returns the comparison (-1/0/1) indicator for two primitives. (These methods already exist on Float/Double).

The methods from SystemUtils can be very useful in reducing arbitrary strings in code:

8) Get common environment variables.
File System.getJavaIoTempDir()
File System.getJavaHomeDir()
File System.getUserHomeDir()
File System.getUserDir()
Returns the java environment variables. There are lots more in SystemUtils that could be added.

Some more null handling methods for primitives - again, Elvis would be a better solution:

9) Convert wrapper to primitive avoiding NPE.
boolean Boolean.booleanValue(Boolean obj, boolean defaultValue)
char Character.charValue(Character obj, char defaultValue)
byte Byte.byteValue(Byte obj)
byte Byte.byteValue(Byte obj, byte defaultValue)
short Short.shortValue(Short obj)
short Short.shortValue(Short obj, short defaultValue)
int Integer.intValue(Integer obj)
int Integer.intValue(Integer obj, int defaultValue)
long Long.longValue(Long obj)
long Long.longValue(Long obj, long defaultValue)
float Float.floatValue(Float obj)
float Float.floatValue(Float obj, float defaultValue)
double Double.doubleValue(Double obj)
double Double.doubleValue(Double obj, double defaultValue)
Safe ways to convert a wrapper to a primitive.
The numeric ones return zero if the default argument isn't specified.
There is also a case for methods to convert arrays of wrappers to arrays of primitives.

These should probably be on a Booleans utility class as per BooleanUtils.

10) Boolean methods for clearer code.
boolean Booleans.isTrue(Boolean booleanObj)
boolean Booleans.isFalse(Boolean booleanObj)
Return true as per the method name, false if null.
boolean Booleans.isNotTrue(Boolean booleanObj)
boolean Booleans.isNotFalse(Boolean booleanObj)
Return true as per the method name, true if null.

11) Negate handling null.
Boolean Booleans.negate(Boolean booleanObj)
TRUE returns FALSE, FALSE returns TRUE, null returns null.

11) Boolean arithmetic.
boolean Booleans.and(boolean[] array)
boolean Booleans.or(boolean[] array)
boolean Booleans.xor(boolean[] array)
boolean Booleans.and(Boolean[] array)
boolean Booleans.or(Boolean[] array)
boolean Booleans.xor(Boolean[] array)
Performs the stated binary maths.

12) Character comparison.
boolean Character.equalsIgnoreCase(char ch1, char ch2)
Compares two characters ignoring case.

These should be constants for empty arrays on common classes:

13) Empty array constants.
Boolean[] Boolean.EMPTY_ARRAY
boolean[] Boolean.EMPTY_PRIMITIVE_ARRAY
Character[] Character.EMPTY_ARRAY
char[] Character.EMPTY_PRIMITIVE_ARRAY
Byte[] Byte.EMPTY_ARRAY
byte[] Byte.EMPTY_PRIMITIVE_ARRAY
Short[] Short.EMPTY_ARRAY
short[] Short.EMPTY_PRIMITIVE_ARRAY
Integer[] Integer.EMPTY_ARRAY
int[] Integer.EMPTY_PRIMITIVE_ARRAY
Long[] Long.EMPTY_ARRAY
long[] Long.EMPTY_PRIMITIVE_ARRAY
Float[] Float.EMPTY_ARRAY
float[] Float.EMPTY_PRIMITIVE_ARRAY
Double[] Double.EMPTY_ARRAY
double[] Double.EMPTY_PRIMITIVE_ARRAY
String[] String.EMPTY_ARRAY
Class[] Class.EMPTY_ARRAY
Object[] Objects.EMPTY_OBJECT_ARRAY
Return true as per the method name, true if null.

Or a better solution might be a method on Class:
T[] Class.emptyArray();
This allows code like:
Boolean.class.emptyArray();

14) Array size.
boolean Arrays.isEmpty(Object[] array)
int Arrays.size(Object[] array)
Where a null array is empty/size-zero.

15) Collection size.
boolean Collections.isEmpty(Collection coll)
int Collections.size(Collection coll)
boolean Collections.isEmpty(Map map)
int Collections.size(Map map)
Where a null collection is empty/size-zero.

Or, even better, add a new interface Sized with a single method to get the size. This would be retrofitted to Collection, Map, String and arrays (of course, technically, thats a language change...).

And some Class utilities for less NPEs when outputting the class name in debugging:

16) NPE safe way to get class name.
String Class.getName(Class cls)
String Class.getSimpleName(Class cls)
String Class.getPackageName(Class cls)
Returns the class name, or null if the input is null.
Again, the null-safe operators would avoid this kind of specific method.

Locale could do with some love, as per LocaleUtils:

17) Parse a locale string.
Locale parse(String localeStr)
Parses the locale string to a locale.

16) Country/Language lists.
List Locale.countriesByLanguage(String langaugeStr)
List Locale.languagesByCountry(String countryStr)
Extracts just countries or languages.

A better solution would be two new classes Country and Language. These would be useful in other places in the JDK, where a locale is used and it should be a country or language.

And the big one that I've missed - safe maths, as per Joda-Time FieldUtils:

18) Add/subtract/multiply/cast safely.
int Math.safeToInt(long value)
int Math.safeNegate(int value)
long Math.safeNegate(long value)
int Math.safeAdd(int value1, int value2)
long Math.safeAdd(long value1, int value2)
long Math.safeAdd(long value1, long value2)
int Math.safeSubtract(int value1, int value2)
long Math.safeSubtract(long value1, int value2)
long Math.safeSubtract(long value1, long value2)
int Math.safeMultiply(int value1, int value2)
long Math.safeMultiply(long value1, int value2)
long Math.safeMultiply(long value1, long value2)
These perform the specified mathematical operation, but throw ArithmeticException, rather than failing quietly, if overflow occurs.

I should also note that there are a whole heap of BigDecimal, BigInteger and String utilities that could be added.

Finally, of course, there are lots of other utility class libraries apart from Commons-Lang. Its simply that Commons-Lang provides a good point to start the discussion.

Feel free to (a) complain about my choices, and (b) suggest your own ideas. Remember to focus on non-string core classes for now.

Tuesday, 27 January 2009

JDK 7 language changes - Everyone votes!

A third vote on language changes has just completed, this time it was online. I'll summarise the results from the three votes in this post.

Three votes

The three votes in question were:

At Devoxx, the topics voted on were:

  • Properties
  • Multi-catch of exceptions
  • Null handling
  • List/Map access using []
  • Extension methods
  • Method pointers
  • Multi line strings
  • Infer generics on the RHS

At JavaEdge and Online the features voted on were:

  • For-each loop over a Map
  • Control over for-each loops (index/remove)
  • List/Map access using []
  • Infer generics on the RHS
  • Multi-catch of exceptions
  • String switch
  • String interpolation
  • Multi line strings
  • Resource management
  • Null handling

The later polls excluded properties as they are specifically excluded for Java 7. They also excluded extension methods and method pointers as these were the least popular options at Devoxx.

Here are the first preference votes for Devoxx, JavaEdge (ranked), JavaEdge, (not-ranked) and Online:




Considering the first to fourth preference votes (first at the bottom in dark green):




Totals

Unfortunately, we can't add the Devoxx figures directly to the rest as the data is incomplete. However, it is useful to add all JavaEdge and Online votes together:


So, what do these results tell us? As always, absolute answers are difficult, because not all voters followed the same rules (online voters clearly didn't rank properly), and Devoxx was asked a different question. However, some things can be established, based not only on total votes but also how the preferences went from 1 to 10.

  • Devoxx voters favoured Infer-generics, Multi-catch and Null-handling.
  • JavaEdge voters favoured Null-handling, String-switch and Multi-catch.
  • Online voters favoured Multi-catch, Null-handling, Infer-generics and String-switch.

So, these four options polled consistently highly in each of the different votes (except Infer-generics which did badly at JavaEdge). This now lends quite significant weight to the question of 'what does the community want' and 'what pain points need addressing'. The small language changes for Java 7 project now has some solid data to work from.

My take is that Multi-catch looks like a strong favourite for inclusion, as does String-switch. Infer-generics had a slightly more mixed reception in JavaEdge, but is popular elsewhere.

The big question is over Null-handling. Three separate votes has ranked it highly, with it taking the highest number of first preference votes in three of the four measured graphs above. There is a clear desire for change and a clear proposal. I hope the opportunity is not missed.

Summary

As more votes stack up, the statistics become more secure. We can now say that out of the ten polled items, the top four are Null-handling, Multi-catch, String-switch and Infer-generics.

Any feedback or thoughts are welcome!

Sunday, 21 December 2008

JDK 7 language changes - JavaEdge votes!

For the past few days I have been in the fabulous country of Israel at the JavaEdge conference. Duing the keynote speech, I presented 10 possible language changes for JDK7, and asked the audience to vote on them.

These results are in more depth than the Devoxx figures simply because we could extract information about each persons preferences. For academics or statisticians the raw data is available in Open Office format.

Given ten language changes, rank them according to priority

So, the question is the same basic question as we asked at Devoxx, but with a different selection of changes to pick from. The results show that 171 people voted correctly (starting from 1 for the first preference, 2 for the second and so on). Another 41 attendees voted mostly corrrectly, skipping one of the prefereces (for example marking a 1st, 2nd, 3rd and 5th preference, but not a 4th). A final 113 attendees didn't follow the instructions at all, and marked multipe 1st preferences, multiple 2nd preferences and so on.

The features voted on were:

  • For-each loop over a Map
  • Control over for-each loops (index/remove)
  • List/Map access using []
  • Infer generics on the RHS
  • Multi-catch of exceptions
  • String switch
  • String interpolation
  • Multi line strings
  • Resource management
  • Null handling

These results are for those who completed the voting according to the rules (171 attendees).

Here are the first preference votes:

Adding the second preference votes:

Adding the third preference votes:

Adding the fourth preference votes:

Adding the fifth preference votes:

Adding the remaining votes (white is didn't vote, black is 'this is a bad idea':

Now those that almost voted according to the rules - votes are adjusted to move everything beyond the missing column up (41 attendees).

All votes:

Now those that voted based on general preference (103 attendees).

All votes:

So, what do these results tell us? (I'm focussing the analysis on those who voted fully according to the rules, as it is hard to interpret the results from those who simply gave arbitrary rankings).

As with the Devoxx results, there is a clear winner - null handling. Null handling had 50 first preference votes, double that of second place string switch and almost a third of all first preferences. This trend continued with almost two thirds placing it in their top four.

Other popular options were String Switch, Multi-catch of exceptions, enhanced for-each loop for Maps, enhancing the for-each loop to be able to remove or find the index and ARM-style resource management.

Unpopular options (especially considering the black 'bad idea' values) were List/Map access using [] and String interpolation (${variable} in strings).

Infer generics and multi-line strings were deemed of relatvely low importance but not particularly objectionable.

The other 144 votes that were not completely according to the rules are harder to interpret. If someone wants to give it a go, feel free to interpret the raw data.

Summary

Firstly, a big thank you to the JavaEdge voters, and to the AlphaCSP team in Israel. Again, we have some really interesting figures from this vote, with null handling again coming out top. Clearly, there needs to be some real thought about whether some form of null handling can be achieved.

Any feedback or thoughts are welcome!

Sunday, 14 December 2008

JDK 7 language changes - Devoxx votes!

Once again, the great Devoxx conference allowed ordinary developers to express an opinion on the future of the Java language. This time, the focus was on prioritising which changes should happen.

The figures given below are of course indicative only. They are based on those Devoxx attendees who actually participated on the whiteboards. Also, the figures are as recorded at the end of Thursday (Friday scores not included). The whiteboard photos are available which provide additional information. Bear in mind that my figures may disagree with the photos in some small way based on when I counted the results relative to when the photos were taken.

Given eight language changes, rank them according to priority

This year, rather than simple "do you like this yes/no" questions, we posed something tougher. Prompted by Alex Buckley, we asked participants to rank eight language change proposals. Voters had to mark the number one against their highest priority, two against their next highest and so on until they had no more priorities. Attendees could also vote against a proposal by marking an 'X'.

The voting system was not the simplest, and we know a few people didn't vote correctly. However, we do believe that the vast majority did vote according to the rules making these results valid. The total number of voters was around 220, so the results have good validity.

Feature Properties Multi catch Null handling List/Map syntax Extension meths Method pointers Multiline Strs Infer generics
1 33 47 70 10 6 8 9 61
2 21 56 38 16 8 10 12 49
3 30 35 27 35 10 15 21 35
4 25 26 15 42 17 13 28 19
5 10 20 15 29 13 25 29 19
6 14 15 8 17 23 21 27 15
7 14 9 2 18 24 25 24 11
8 26 19 2 9 19 23 32 8
X 29 1 12 8 28 24 15 0
 
Total Votes 202 228 189 184 148 164 197 217
Total votes
(excluding X)
173 227 177 176 120 140 182 217
Weighted average 4.08 3.41 2.49 4.32 5.36 5.25 5.16 3.07

Here are the first preference votes:

Adding the second preference votes:

Adding the third preference votes:

Adding the fourth preference votes:

Adding the remaining votes:

So, what do these results tell us?

Well, they are in fact amazingly clear. Null-handling was the first preference favourite by a small margin, ahead of Infering RHS generics and Multi-catch of exceptions. However, if particpants had been given just three votes, then these three would have scored almost exactly equal (135/145/138) and over double that of List/Map access (61).

Next in line (ignoring properties) was List/Map access using [], which can be seen by the big jump in third and fourth preference votes. Fifth was Mult-line strings, which developers seem to not be that fussed about.

Finally, extension methods and method pointers (method references) performed poorly in the vote.

Properties was shown to be the most divisive, with both a large number of votes for and against, and fewer in the middle preferences. For example, notice the high number of first preferences, but dropping back when adding second and third preferences. In addition, properties has a high number of low preferences and votes against (coloured black). Since properties isn't going to be included in JDK 7, the properties column is really just an interesting comparison data point.

Obviously in a free vote like this without any explanations, it is easy for people to not vote for items they don't understand. This could explain some the lower scores for Extension methods and Method references (see the total number of votes cast to confirm this). However, even taking this into account, these two don't seem to have as much support as the big three of Null-handling, Infering RHS generics and Multi-catch exceptions

It should also be noted that the graphs and the weighted averages are in line with one another.

Other language changes

In addition to the ranking above, there were some other votes.

The vote on closures was split 50/50:

Yes41
No41

The vote on abstract enums showed a majority in favour:

Yes24
No18

The vote on ARM (resource management) showed a large majority in favour:

Yes64
No11

The vote on some form of delegation showed a majority in favour:

Yes36
No9

The vote on for each over a string showed a majority in favour:

Yes34
No21

Summary

Firstly, a big thank you to the Devoxx voters, and to Stephan and the Devoxx organisers. I think this exercise was a huge success in participation. I'm certainly not in favour of language design by democracy, but I am very much in favour of gathering large scale information on what really causes developers pain. Clearly, handling nulls, RHS generics and catching exceptions are three big issues.

I hope to repeat the exercise again soon. And if any JUG (public or company internal) wants to do the same (maybe with different proposals) then I'd recommend it (and I've even got an Open Office presentation if you want some material - just drop me a line).

Any feedback or thoughts are welcome!

Tuesday, 9 December 2008

Java 7 - small language changes

Todays news that there are likely to be language changes in JDK 7 was a bit of a surprise. It seemed like the chance had passed.

Small language changed for JDK 7

Joe's post isn't very long, but it is clear.

  • "I'll be leading up Sun's efforts" - so its supported by Sun
  • "develop a set of ... language changes - so its more than one change
  • "small language changes" - small means no closures or properties
  • "we'll first be running a call for proposals" - community involvment
  • "in JDK 7" - in the next version (but why does the blog not say Java 7?)

I've used this blog, and previous visits to JavaPolis (now Devoxx) to discuss possible language changes. Some have been good ideas, others not so good. The main point was to provide a place for discussion.

The next phase after that was to implement some of the language changes. This has been achieved with the Kijaro project. As far as I'm concerned, anyone can write up an idea for a Java language change, and then I'll provide commit access at Kijaro for it to be implemented in javac - no questions asked.

Expectations

So, before we all submit lots of crazy ideas and get carried away, lets remember that Sun provided some hints at JavaOne 2008. This presentation includes the following as ruled out:

  • Operator overloading (user defined)
  • Dynamic typing
  • Macros
  • Multiple dispatch / multi-methods

And the following as 'under consideration':

  • Multi-catch in exceptions
  • Rethrowing exceptions

The following are listed as 'long term areas of interest':

  • Parallel algorithms
  • Versioning of interfaces
  • Delegation
  • Extension methods
  • Structural typing
  • Pluggable literal syntaxes

So, there is already quite a wide list on the table. Plus, there were other ideas suggested at last years JavaPolis, by both Josh and Neal:

  • Variable declaration type inference (for generics)
  • Enum comparisons
  • Switch statement for strings
  • Chained invocations, even when method returns void

In addition to all the above, I strongly suspect that there isn't going to be a chance to tackle problems with generics. This is similar to closures and properties. There isn't the timesclae or manpower to tackle these big issues in the timeframe being talked about (especially now Neal Gafter works for Microsoft).

My ideas

Well, I'll mostly save those for another day. But I would like to see a proper consideration of enhancements to help with null handling. And enhancments to the for-each loop.

Saying NO!

Finally, an appeal to Sun. Many in the community are deeply sceptical of any language changes at this point. The message should be simple - people need to feel that there is a clear means to vote or argue AGAINST a proposal, just as much as to make suggestions FOR change. Although I don't expect to make much use of the facility, I know there are many that do want to express this opinion.

Summary

This is a new departure for Sun in so openly asking for ideas from the community. We need to respond and reply with thoughtful ideas for what will and will not work.

Friday, 28 September 2007

JSR-275 - Suitable for Java 7?

I've been evaluating JSR-275 - Units and Quantities tonight in relation to JSR-310. Its not been pretty.

JSR-275 - Units and Quantities

JSR-275 is a follow on from JSR-108, and aims to become part of the standard Java library in the JDK. It provides a small API for quantities and units, and a larger implementation of physical units, conversions and formatting. The goal is to avoid using ints for quantities, with their potential for mixing miles and metres.

So where's the problem?

Well, it starts with naming. There is a class called Measure which is the key class. But its what I would call a quantity - a number of units, such as 6 metres or 32 kilograms.

Measure is generified by two parameters. The first is the value type. You'd expect this to be a Number, but weirdly it is any class you like.

You'd expect the second generic parameter to be the unit type, right? Er, no. It's the Quantity. So, not only is the quantity class not called Quantity, there is another class which doesn't have much to do with a quantity that is called Quantity. Confused yet?

The unit class is at least called Unit. Unit also has a generic parameter, and again its Quantity.

So, what is this mysterious Quantity class in JSR-275?

Well, its the concept of length or temperature or mass. Now actually that is a very useful thing for JSR-275 to have in the API. By having it in the API, it allows the generic system to prevent you from mixing a length with a mass. Which must be a Good Thing, right?

 Measure<Integer, Length> distance = Measure.valueOf(6, KILO(METRES));
 int miles = distance.intValue(MILES);

The first thing to notice is that the variable is held using a Length generic parameter. There is no support in JSR-275 to specify the variable to only accept metres or miles. Personally, I think thats a problem.

The second thing to notice is how easy conversion is. It just happened when it was requested. But is that what you necessarily want? We just converted from kilometres to miles without a thought. What about lost accuracy? Are those units really compatible?

Well now consider dates and times:

 Measure<Integer, Duration> duration = Measure.valueOf(3, MONTHS);
 int days = duration.intValue(DAYS);

Er, how exactly did we manage to convert between months and days? What does that really mean? Well, assuming I've understood everything, what it does is use a definition of a year as 365 days, 5 hours, 49 minutes, and 12 seconds, and a month being one twelth of that. It then goes ahead and does the conversion from months to days using that data.

I doubt that the result will be what you want.

In fact, perhaps what has happened here is that we have substituted the unsafe int with a supposedly safe class. With JSR-275 we relax and assume all these exciting conversions will just work and nothing will go wrong. In short, we have a false sense of security. And thats perhaps one of the worst things an API can do.

I then looked at the proposal for integrating JSR-275 and JSR-310. One idea was for the JSR-310 duration field classes (Seconds, Minutes, Days, Months, etc) to subclass Measure. But that isn't viable as Measure defines static methods that are inappropriate for the subclasses. Measure also defines too many regular methods, including some that don't make sense in the context of JSR-310 (or at least the JSR-310 I've been building).

Looking deeper, what I see is that JSR-275 is focussed on conversions between different units. There is quite a complex API for expressing the relationships between different units (multipliers, powers, roots, etc). This then feeds right up to the main public API, where a key 'service' provided by the API is instant conversion.

But while conversion is important, for me it has come to dominate the API at the expense of what I actually wanted and expected. My use case is a simple model to express a quantity - a Number plus a Unit.

Alternative

So, here is my mini alternative to JSR-275:

 public abstract class Quantity<A extends Number, U extends Unit> {
  public abstract A amount();
  public abstract U unit();
 }
 public abstract class Unit {    // grams or celcius
  public abstract String name();
  public abstract Scale scale();
 }
 public abstract class Scale {   // mass or temperature
  public abstract String name();
 }
 
 Quantity<Integer, MilesUnit> distance = ...

So, what have we lost? Well, all the conversion for a start. In fact, all we actually have is a simple class, similar to Number, but for quantities. And the unit is very bare-bones too.

We've also lost some safety. There is now no representation of the distance vs duration vs temperature concept. And that could lead us to mix mass and distance. Except that the API will catch it at runtime, so its not too bad.

And what have we gained? Well its a much smaller and simpler API. But less functional. However, by being simpler, its easier for other teams like JSR-310 to come along and add the extra classes and conversions we want. For example, implementations of Quantity called Days and Months that don't provide easy conversion.

In essence, this is just the quantity equivalent of Number - thus its a class which the JDK lacks.

I'm sure there are many holes in this mini-proposal (I did code it and try to improve on it, but ran into generics hell again). The main thing is to emphasise simplicity, and to separate the whole reams of code to do with conversion and formatting of units. I'm highly unconvinced at the moment that the conversion/formatting code from JSR-275 belongs in the JDK.

Summary

Having spent time looking at JSR-275 I'm just not feeling the love. Its too focussed on conversion for my taste, and prevents the simple subclassing I actually need.

Opinions welcome on JSR-275!