Monday, July 31, 2006

Peter Norvig's Infrequently Answered Questions

Here's a Java resource I wish I had known about long ago: Peter Norvig's Java IAQ.

UPDATE: Thanks to anonymous for pointing out I mispasted in the link!

Saturday, July 29, 2006

A Java trick with varargs to enforce argument count

Perhaps you've seen this before, but it is new to me:

public void doSomethingAmazing(
        final String firstArgument,
        final String... restOfArguments) {
    // Do something amazing with the arguments
}

What is the point of firstOne and restOfThem (besides looking a little LISPy)?

Fortunately, the coder had this comment for the method: Change from checking at runtime for one or more arguments to syntatically enforcing a mandatory first argument and optional list of remaining arguments. A quick check showed the previous version as:

public void doSomethingAmazing(
        final String... arguments) {
    // Do something amazing with the arguments
}

Aha, how clever! Whereas before the call:

doSomethingAmazing();

compiled but at runtime threw an IllegalArgumentException for empty arguments[], now the same call is a syntax error caught by the compiler. The correct new call is:

doSomethingAmazing("wonderful");

I like it.

UPDATE: Paul Holser points out to me that he uses this trick in the excellent JAggregate. As I reviewed that code within the past several months, I now realize that it is most likely I had already seen this trick there first. Paul is a clever guy, and deserves the credit.

Wednesday, July 19, 2006

The double inheritance pattern in Java

Java is a single inheritance language, yes? Generics adds a new wrinkle to that, however. Consider this problem:

You have a class hierarchy you wish to wrap. For instance, you want wrapped versions of JTextComponent and its subclasses which implement additional functionality or default behaviors. So the first wrapping looks like this:

public class MyTextComponent
        extends JTextComponent {
    // ...
}

The second wrapping looks like this:

public class MyTextField
        extends JTextField or MyTextComponent {
    // ...
}

Oops! What should the second wrapper extend?

Generics provides a neat, if wordy, solution for this problem. Have the wrapper hierarchy extend only within itself, and have generic types extend the wrapped hierarchy. The wrapper hierarchy delegates to the wrapped one. Thus:

public class LabeledTextComponent<F extends JTextComponent>
        extends Box { // Box is just illustrative
    protected final F field;

    private final JLabel label;

    protected LabeledTextComponent(final F field,
            final String labelText) {
        super(BoxLayout.LINE_AXIS);

        this.field = field;
        label = new JLabel(labelText, SwingConstants.TRAILING);

        label.setLabelFor(field);
        
        add(label);
        add(field);
    }

    // ... public constructors

    // delegates via field specific to JTextComponent

    public String getText() {
        return field.getText();
    }

    public void getText(final String text) {
        field.setText(text);
    }

    // ... other delegates

    // methods specific to LabeledTextComponent

    public JLabel getLabel() {
        return label;
    }
}

public class LabeledTextField<F extends JTextField>
        extends LabeledTextComponent<F> {
    protected LabeledTextField(final F field,
            final String labelText) {
        super(field, labelText);
    }

    public LabeledTextField(final String labelText) {
        super(new JTextField(), labelText);
    }

    public LabeledTextField(final int columns,
            final String labelText) {
        super(new JTextField(columns), labelText);
    }

    // ... other public constructors, etc.
}

And a further example:

public class LabeledPasswordField<F extends JPasswordField>
        extends LabeledTextField<F> {
    protected LabeledTextField(final F field,
            final String labelText) {
        super(field, labelText);
    }

    // ... public constructors

    // delegates via field specific to JPasswordField

    public char[] getPassword() {
        return field.getPassword();
    }

    public void getPassword(final char[] password) {
        field.setPassword(password);
    }

    // ... other delegates
}

Generics combined with delegates simulates a kind of multiple inheritance similar to mixins. One can extend the idea one step further:

public interface Required {
    /** Checks if the field requires text to be valid. */
    boolean isRequired();

    /** Toggles that the field requires text to be valid. */
    void setRequired(final boolean required);

    /** Checks if the field is required and if the text is missing. */
    boolean isMissing();
}

public class RequiredTextField extends JTextField
        implements Required {
    private boolean required;

    // Required
    public boolean isRequired() {
        return required;
    }

    public void setRequired(final boolean required) {
        this.required = required;
    }

    public boolean isMissing() {
        return required
                && null != getText();
                && getText().length() > 0;
    }
}

public class RequiredLabeledTextField
        <F extends JTextField & Required>
        extends LabeledTextField<F>
        implements Required {
    protected RequiredLabeledTextField(final F field,
            final String labelText) {
        super(field, labelText);
    }

    // Required
    public boolean isRequired() {
        return field.isRequired();
    }

    public void setRequired(final boolean required) {
        field.setRequired(required);
    }

    public boolean isMissing() {
        return field.isMissing();
    }
}

Now it is simple to glue it all together cleanly, maintaining separation of concerns and working through interfaces based on capabilities rather than concrete classes.

Generics to the rescue!

NB — I relied heavily on my background in C++ templates for conceptualizing this pattern. But I believe it likely I am treading no new ground. If you know an earlier or better reference for this pattern, please drop me a line. I want to give credit to where it is due.