Thursday, September 11, 2008

Interface Chaining

I was recently talking with my friend Mark Volkmann about an application framework he was developing. The framework, named WAX, is a very nice Java API for writing out XML. Despite it's small size, it's much nicer than any other XML writing API I've ever seen and you should go check it out.

As part of the API, Mark implementing method chaining. This allows for very compact code that is still quite easy to read. For example, you could produce this XML:

<?xml version="1.0" encoding="UTF-8"?>
<car year="2008">
<model>Prius</model>
</car>

with just this code::

WAX wax = new WAX(WAX.Version.V1_0);
wax.start("car").attr("year", 2008)
.start("model" ).text( "Prius").close();

Much of the compactness comes from the fact that each method called returns the WAX object, allowing the developer to chain method calls together.

As we were discussing the code, the topic of incorrect ordering of calls came up. For example, what happens if you try to call the attr method to create an attribute after already creating some text inside the element with the text method?

Because WAX is a streaming API, you can't 'go back' and add an attribute in the start element tag after having already 'moved on' to putting text in the body of the element. For example, what if I tried to create an attribute to the model of the car after putting text in it, like this:

WAX wax = new WAX(WAX.Version.V1_0);
wax.start("car").attr("year", 2008)
.start("model" ).text( "Prius").attr( "trim", "GT" ).close();

WAX detects this situation and throws an exception at runtime, which it should do. But I'm a fan of static type checking. I love having tools do as much checking for me as possible. So I suggested to Mark that he create a set of interfaces. Each interface would contain only the methods that make sense at the current point in the output stream. This would allow the compiler to catch invalid method invocations. Even better, modern IDEs like IDEA would flag the method invocation visually even before compilation.

For example, if we arrange for the text method to return an interface which does not have an attr method, then the compiler will catch it and the IDE will flag the error visually. For example, in IDEA, the error is flagged like this:



Now we get the compactness of runtime exceptions (which Mark really likes) and static checking (which I really like). I did some looking around and couldn't find a design pattern that really fits. A number of people suggested that this was an example of a domain-specific language (DSL). But to my thinking, something that deserves the moniker of 'language' should be more involved than simply constructing some interfaces so that static checking is applied.

But whatever you call it, I think it's a useful design pattern than can be applied in other situations to make for clean, compact, yet statically checked APIs.

Thursday, July 17, 2008

Create inbox items in OmniFocus from the dashboard

I am a very heavy user of OmniFocus. It has many ways to enter information. For example, you can use the "Quick Entry Window", which is great for creating an item with a project, context, and optional description.



But sometimes I am not in OmniFocus and don't have any text selected. This means there is nothing for OmniFocus to treat as a clipping. As a result it won't bring up the quick entry window.

So, I wrote my first Dashboard widget. It has a text area where you type the text for your item and a "Send It" button. When you click the button or hit enter in the text area, a new item is sent to your inbox.



I submittted it to Apple for inclusion in their download area for dashboard widgets download site. Until it shows up there, you can get it directly from here.

[Updated 2008-07-17 21:05]

Someone pointed out that I had forgotten that there is a separate keystroke to bring up the quick entry window without having any text selected. This eliminates much of the purpose of this widget unfortunately, unless you spend a lot of time in the dashboard anyway. At least it was a good learning exercise... :-)

Monday, May 05, 2008

Groovy Type Handling is Broken

Here's a very simple Java program snippet:

List<Integer> list = new ArrayList<Integer>();
Collection<Integer> col = list;
list.add( 2 );
list.add( 1 );
list.add( 0 );
System.out.println( list );
col.remove( 0 );

Run this and you'll get what you'd expect. Before using the col reference to remove the integer/Integer with value 0 (zero), you see:

[2, 1, 0]

Then, after calling remove on the collection, we see the integer/Integer with value zero is gone (that's the one we said to remove):

[2, 1]

Groovy says that it allows you to use types and will honor them at runtime. But it doesn't.

Take the same snippet of code and run it as a Groovy script. Remember that the Collection interface has a remove method, and that method expects you to pass it an object which it will remove from the collection. So we would expect to see the same result as in Java. But we don't. Instead, we get this:

[2, 1, 0]
[1, 0]

Groovy has removed the Integer with a value of 2! It did this because of Groovy's 'multi-methods'. Groovy looked at the real type of col, which is an ArrayList. It then found a remove method that takes an integer/Integer. That method removes the Nth item from the list. It used that method and removed the zero-th item (the one with a value of 2).

But remember, I invoked the remove. method through the Collection interface. The collection interface does not have a method taking an integer/Integer but it does have a remove method taking the object to be removed!

This is a truly awful result. It removes our ability to reason about how code will behave by looking at the types involved. In order to know how this will behave, I cannot make any use of the type information; in fact the type information is downright misleading. Even worse, as the type system evolves and new classes are introduced, new methods with entirely different signatures may get invoked.

This approach to handling types is essentially broken. The claim that Groovy honors types (even the weakened form of honoring it by doing casts at runtime) is flat out wrong.

Groovy needs to either start honoring type information, or get rid of it.

Thursday, April 24, 2008

Insidious Coupling

This will get to the topic of code coupling soon enough, but bear with me for a bit of background.

I like to use the 'fail fast' approach to my code. This means that invalid inputs cause a failure in the code as quickly as possible. Perhaps the simplest example of this in the JDK is the collections classes, whose iterators fail as soon as they detect that the underlying collection object has been modified. This allows them to avoid synchronization costs while also detecting unsafe usage.

In my own code, the most common situation where I find fast-fail code is in constructors. If an argument the constructor cannot be null (either because it will be used in the constructor, saved to a field, or both), I check that the object reference is not null. For example:

public class Foo {
// ...
public Foo( Bar b ) {
// Check that b is not null
// rest of constructor...
}
}

I started out performing this check with an if statement:

public class Foo {
// ...
public Foo( final Bar b ) {
if ( b == null ) {
throw new IllegalArgumentException( "Bar b cannot be null" );
}
// rest of constructor...
}
}

This gets us a pretty understandable stack trace:

Exception in thread "main" java.lang.IllegalArgumentException: Bar b cannot be null
at org.sandbox.Foo.(Foo.java:10)
at org.sandbox.SimpleDoesStuff.doIt(SimpleDoesStuff.java:11)
at org.sandbox.Baz.main(Baz.java:10)

But this Java code is pretty verbose, especially if you have multiple arguments to check. After that I tried creating a static method named assureNotNull which would perform the check:

public class Foo {
// ...
public Foo( final Bar b ) {
assureNotNull( b );
// rest of constructor...
}
//...
private static void assureNotNull( final Object o ) throws IllegalArgumentException {
if ( o == null ) {
throw new IllegalArgumentException( "Object cannot be null" );
}
}
}

This has the unfortunate consequence that it becomes harder to track down the nature of the problem.

Exception in thread "main" java.lang.IllegalArgumentException: Object cannot be null
at org.sandbox.Foo.assureNotNull(Foo.java:14)
at org.sandbox.Foo.(Foo.java:9)
at org.sandbox.SimpleDoesStuff.doIt(SimpleDoesStuff.java:11)
at org.sandbox.Baz.main(Baz.java:10)

The stack trace on the exception shows assureNotNull as the source of the exception, which while strictly true doesn't clearly show that the real problem was with someone passing a null Bar to the Foo constructor. This can be mitigated to some degree by taking an description as argument:

public class Foo {
// ...
public Foo( final Bar b ) {
assureNotNull( b, "Bar b cannot be null" );
// rest of constructor...
}
//...
private static void assureNotNull( final Object o, final String msg ) throws IllegalArgumentException {
if ( o == null ) {
throw new IllegalArgumentException( msg );
}
}
}

This provides a somewhat more helpful exception message but the method generating the exception is still 'off by one':

Exception in thread "main" java.lang.IllegalArgumentException: Bar b cannot be null
at org.sandbox.Foo.assureNotNull(Foo.java:14)
at org.sandbox.Foo.(Foo.java:9)
at org.sandbox.SimpleDoesStuff.doIt(SimpleDoesStuff.java:11)
at org.sandbox.Baz.main(Baz.java:10)

And even with this semi-fix to help find the cause of the problem, we're still left with recreating this method in every class. From here the logical next step is to centralize the method. We can do this with an Assertions class:

public class Assertions {
// ...
public static void assureNotNull( final Object o, final String msg ) throws IllegalArgumentException {
if ( o == null ) {
throw new IllegalArgumentException( msg );
}
}
// ...
}

Now, our Foo constructor becomes simpler:

import org.acme.Assertions;

public class Foo {
// ...
public Foo( final Bar b ) {
Assertions.assureNotNull( b, "Bar b cannot be null" );
// rest of constructor...
}
//...
}

And with Java 5's static imports, we can even simplify it further:

import static org.acme.Assertions.assureNotNull;

public class Foo {
// ...
public Foo( final Bar b ) {
assureNotNull( b, "Bar b cannot be null" );
// rest of constructor...
}
//...
}

But we still have the wrong method as the first listed in the stack trace:

Exception in thread "main" java.lang.IllegalArgumentException: Bar b cannot be null
at org.acme.Assertions.assureNotNull(Assertions.java:9)
at org.sandbox.Foo.(Foo.java:7)
at org.sandbox.SimpleDoesStuff.doIt(SimpleDoesStuff.java:11)
at org.sandbox.Baz.main(Baz.java:10)

Since all of us Java developers are big on frameworks, we might even take it to the 'next level'. Why not centralize the Assertions in some common framework? If the Assertions class were in a common framework, the thinking goes, then we'd all be able to use it everywhere. That consistency would really help us read unfamiliar code.

Ignoring the issue of getting any set of developers of size greater than one to agree on anything, especially a basic assertions framework used everywhere, we've just introduced insidious code coupling where it really doesn't belong. In our desire to achieve clarity, brevity, and avoid redundancy, we've coupled code together. If we have a common class in our framework, all the classes in the framework are now coupled to it and indirectly to each other. If we move the class to a generic framework, we externalize the coupling, making it even broader. This coupling introduces many hazards for versioning and incompatibility problems that come with the independent evolution of code.

So, what choice are we left with? Well, we could always depend upon the runtime itself to generate an exception for us. We can do this quite briefly, with less redundancy of code than the other approaches, and with zero coupling:

public class Foo {
// ...
public Foo(Bar b) {
b.getClass(); // Assure not null
}
}

This code is quite short, and generates a NullPointerException with the top element pointing to exactly the line of code where the problem occurred:

Exception in thread "main" java.lang.NullPointerException
at org.sandbox.Foo.(Foo.java:7)
at org.sandbox.SimpleDoesStuff.doIt(SimpleDoesStuff.java:11)
at org.sandbox.Baz.main(Baz.java:10)

This code also avoids nearly all redundancy, and I think after seeing it once it becomes quite clear. As a bonus, it's easy to create a macro in any modern IDE to help in generating the code.

Sometimes, the right solution to a problem is not abstracting code into a separate method/class/framework.

Friday, March 07, 2008

Something else Apple Gets Right

Eric Burke made a reference to the work Apple puts into making their applications simple but capable. He also gave Google as an example. That item produced quite a few comments and Eric followed up with more details. Again, the discussion wasn't just about Apple but the company was again an example of hard work making things simple and functional. I agree with his comments, and remembered another example of Apple's efforts toward elegant designs.

For as many years as I can remember, the Apple website has had simple URLs to get to various parts of the website. For example:

Yes, other sites do this now. But Apple was doing this many years ago, long before competitor's sites.

This seemingly simple idea makes it much easier to navigate their web site for the vast majority of people going to the site. It allows people to get more quickly to the area they want. Without this, the task becomes much more involved:
  1. Visit the home page

  2. Parse the layout

  3. Find the navigation links

  4. Find the right link - if it's not there guess where to drill down

  5. Get to where you wanted to go

Wednesday, February 13, 2008

An alternate syntax for Java closures

I'm no expert on the details of the closures proposals. I do think if we're going to put closures into the language, we need to make them complete, full-fledged closures. Generics are a mess precisely because the semantics and features were compromised for the goal of getting it into the language.

But one thing I do know about the BGGA closures proposal is that I don't like the syntax. Take the example in Weiqi Gao's recent Java Quiz:

public class Fib {
private static {int=>int} fib = { int n =>
n==0 ? 0 :
n==1 ? 1 :
fib.invoke(n-1) + fib.invoke(n-2)
};

public static void main(String[] args) {
System.out.println(fib.invoke(6));
}
}

To me, this is just hard to read. The whole "=>" thing seems like a weak attempt to create a new lexical character and is too visually similar to ==, >>, etc. I also don't like the 'invoke' syntax. I was discussing this with Weiqi the other day and came up with a syntax that I like better.

public class Fib {
private static {int # int} fib = { # int n #
n==0 ? 0 :
n==1 ? 1 :
#fib(n-1) + #fib(n-2)
};

public static void main(String[] args) {
System.out.println(#fib(6));
}
}

Note that you could also invoke fib like this:

System.out.println(#Fib.fib(6));

I wonder what other people think of this alternative?

Monday, November 12, 2007

The Wall of Erasure

I mentioned the term "Wall of Erasure" in my previous post about Iterator adapters. My friend Weiqi Gao described it best in his blog entry where he said 'Every really cool idea involving Java generics will invariably lead to insurmountable difficulties the root cause of which is erasure'.

I just got a chance to read Eric Burke's latest blog entries, and he too has hit the Wall of Erasure (some commentors are suggesting it's not "all" erasure's fault, but that's a red herring).

Monday, November 05, 2007

Unit Testing Simple Code

I just read Alex Miller's blog entry where he states quite nicely why unit testing even very simple code is not dumb. He posted because of Eric Burke's excellent discussion of the matter.

I really don't have much more to add, except to add one more voice to those who state that unit testing seemingly trivial code is important. I will say that I've actually caught silly mistakes (like failing to set a field to the correct value in a constructor) with simple unit tests. Also, writing tests for such code lets me spend more time thinking about the hard parts of the problem and less time examining 'simple' code to make sure it is correct.

Sunday, November 04, 2007

Java 5+ Iterator Adapters

I've been working with Java Generics more lately, and have run smack into the "Wall of Erasure". I'm referring to the fact that generics disappear in the bytecode. As you probably know, generics were a targeted feature at a time when Sun was attempting to avoid changing the Java Virtual Machine (JVM). They really wanted to maintain backward compatibility. So, this compromise was put forth to maintain backward compatibility. In a classic case of irony, other changes forced a change the JVM in the same release that gave us generices, but the compromised version of generics stayed. So we are stuck with half an implementation of generics.

Recently, I've been doing work with interfaces and extending interfaces, as in:

public interface Superclass {
// ...
}

public interface Subclass extends Superclass {
// ...
}

I have classes which implement a third interface:

public interface DoesStuff {
Iterator<Superclass> iterator();
// ...
}


You would think that an implementation of DoesStuff could return an Iterator for the iterator method:

public class MyClass implements DoesStuff {
// ...
private Set<Subclass> myThings = new HashSet<Subclass>();
// ...
public Iterator<Superclass> iterator() {
return myThings.iterator();
}
// ...
}

Unfortunately, the Wall of Erasure means we can't do this. Try it for yourself if you don't believe me.


So, what to do? Happily, there is a simple answer. We create an adapter that adapts the subclass iterator to the superclass iterator:


/**
* Adapts a derived class iterator to a base class.
*/
public class IteratorAdapter<B, D extends B> implements Iterator<B> {
private Iterator<D> d;

public IteratorAdapter(Iterator<D> aD) {
d = aD;
}

public boolean hasNext() {
return d.hasNext();
}

public B next() {
return d.next();
}

public void remove() {
d.remove();
}
}

The sad thing is that this shouldn't be necessary. It's trivial. It shouldn't have to be written by developers. The simplicity of this is a clear sign that we need to tear down the Wall of Erasure.

Will it happen any time soon? I hope so. Though I'm hearing talk that "erasing erasure" is probably off the table for Java 7. That would be a truly sad thing.

Friday, October 26, 2007

Making BufferedReader Iterable

I was reading recently about a issues around reading an entire file into a string. I pretty much never do that, since I like my code to be robust even in the face of very large files. But it did get me thinking about reading in lines of a file one at a time. I do have reason to do that on occasion.

Originally, I might have done it something like this:

File file = ...
BufferedReader br = new BufferedReader(new FileReader(file));
String line = br.readLine();
while ( line != null ) {
// Do something with line
line = br.readLine();
}

That's not bad, but I've been working with Ruby lately and really like the terse yet easy-to-read nature of the code. We can improve the above code with a for loop:

File file = ...
BufferedReader br = new BufferedReader(new FileReader(file));
for (String line = br.readLine(); line != null; line = br.readLine()) {
// Do something with line
}

Better, but still not great. Now, what if the BufferedReader were Iterable? It isn't, but we can wrap an Iterable around it. First, let's look at usage:

File file = ...
BufferedReaderIterable bri = new BufferedReaderIterable(new BufferedReader(new FileReader(file)));
for (String read : bri) {
// Do something with the line
}

Very nice. So, all we need is to implement BufferedReaderIterable. Happily, it's quite simple:

public class BufferedReaderIterable implements Iterable<String> {

private Iterator<String> i;

public BufferedReaderIterable( BufferedReader br ) {
i = new BufferedReaderIterator( br );
}
public Iterator iterator() {
return i;
}

private class BufferedReaderIterator implements Iterator<String> {
private BufferedReader br;
private java.lang.String line;

public BufferedReaderIterator( BufferedReader aBR ) {
(br = aBR).getClass();
advance();
}

public boolean hasNext() {
return line != null;
}

public String next() {
String retval = line;
advance();
return retval;
}

public void remove() {
throw new UnsupportedOperationException("Remove not supported on BufferedReader iteration.");
}

private void advance() {
try {
line = br.readLine();
}
catch (IOException e) { /* TODO */}
}
}
}

It would be nice if we could make the construction cleaner. What if BufferedReaderIterable had a constructor that took a File?


public class BufferedReaderIterable implements Iterable<String> {

private BufferedReader mine;
private Iterator<String> i;

public BufferedReaderIterable( BufferedReader br ) {
i = new BufferedReaderIterator( br );
}

public BufferedReaderIterable( File f ) throws FileNotFoundException {
mine = new BufferedReader( new FileReader( f ) );
i = new BufferedReaderIterator( mine );
}
public Iterator<String> iterator() {
return i;
}

private class BufferedReaderIterator implements Iterator<String> {
private BufferedReader br;
private String line;

public BufferedReaderIterator( BufferedReader aBR ) {
(br = aBR).getClass();
advance();
}

public boolean hasNext() {
return line != null;
}

public String next() {
String retval = line;
advance();
return retval;
}

public void remove() {
throw new UnsupportedOperationException("Remove not supported on BufferedReader iteration.");
}

private void advance() {
try {
line = br.readLine();
}
catch (IOException e) { /* TODO */}
if ( line == null && mine != null ) {
try {
mine.close();
}
catch (IOException e) { /* Ignore - probably should log an error */ }
mine = null;
}
}
}
}

Now, usage is even cleaner:

File file = ...
BufferedReaderIterable bri = new BufferedReaderIterable(file);
for (String read : bri) {
// Do something with the line
}

[Editorial Note: Updated to put the template angle brackets back in after Eric Burke noticed Blogger was eating them]