Skip to content

Universal Type Inference is a Bad Thing

9
Apr
2008

Recently, Scala has been wowing developers with its concise syntax and powerful capabilities, but perhaps its most impressive feature is local type inference.  When the intended type for an element is obvious, the Scala compiler is able to make the inference and there is no need for any additional type annotations. 

While this is extremely useful, it falls quite a bit short of the type inference mechanisms available in other languages such as Haskell and ML.  Many people have pointed out that Scala doesn’t go as far as it could in its inference, forcing the use of type annotations when the type could easily be inferred by the compiler.  To understand this claim, it’s necessary to consider an example from a language which does have such universal type inference.  Consider the following function:

fun sum nil init = init 
 | sum (hd::tail) init = hd + (sum tail init)

For those of you not familiar with ML or its derivatives, this is a simple curried function which traverses a given list, adding the values together with an initial value given by init.  Obviously, it’s a contrived example since we could easily accomplish the above using a fold, but bear with me. 

The function has the following type signature: int list -> int -> int.  That is to say, the ML compiler is able to infer the only possible type which satisfies this function.  At no point do we actually annotate any specific nominal type.  Clarity aside, this seems like a pretty nifty language feature.  The ML compiler actually considers the whole function when inferring type, so its inferences can be that much more comprehensive.  Scala of course has type inference, but far less universal.  Consider the equivalent function to the above:

def sum(list:List[Int])(init:Int):Int = list match {
    case hd::tail => hd + sum(tail)(init)
    case Nil => init
  }

Obviously, this is a lot more verbose than the ML example.  Scala’s type inference mechanism is local only, which means that it considers the inference on an expression-by-expression basis.  Thus, the compiler has no way of inferring the type of the list parameter since it doesn’t consider the full context of the method.  Note that the compiler really couldn’t say much about this method even if it did have universal type inference because (unlike ML) Scala allows overloaded methods and operators.

Because of the relative verbosity of the Scala example when compared to ML, it’s tempting to claim that ML’s type inference is superior.  But while ML’s type inference may be more powerful than Scala’s, I think it is simultaneously more dangerous and less useful.  Let’s assume that I was trying to write the sum function from above, but I accidentally swapped the + operator for a :: on the second line:

fun sum nil init = init 
 | sum (hd::tail) init = hd :: (sum tail init)

The ML compiler is perfectly happy with this function.  Such a small distinction between the two, but in the case of the second (incorrect) function, the type signature will be inferred as the following: 'a list -> 'a list -> 'a list (the 'a notation is equivalent to the mathematical ).  We’ve gone from a curried function taking an int list and an int returning an int value to a function taking two list values with arbitrary element types and returning a new list with the same type; and all we did was change two characters.

By contrast, the same mistake in Scala will lead to a compiler error:

def sum(list:List[Int])(init:Int):Int = list match {
    case hd::tail => hd :: sum(tail)(init)    // error
    case Nil => init
  }

The error given will be due to the fact that the right-associative cons operator (::) is not defined for type Int.  In short, the compiler has figured out that we screwed up somewhere and throws an error.  This is very important, especially for more complicated functions.  I can’t tell you how many times I’ve sat and stared at a relatively short function in ML for literally hours before figuring out that the problem was in a simple typo, confusing the type inference.  Of course, ML does allow type annotations just like Scala, but it’s considered to be better practice to just allow the compiler to infer things for itself.

ML’s type inference ensures consistency, while Scala’s type inference ensures correctness.  Obviously, “correctness” is a word which gets bandied about with horrific flippancy, but I think in this case it’s merited.  The only thing that the ML type inference will guarantee is that all of your types match.  It will look through your function and ensure that everything is internally consistent.  Since both the correct and incorrect versions of our sum function are consistent, ML is fine with the result.  Scala on the other hand is more restrictive, which leads to better assurance at compile-time that what you just did was the “right thing”.  I would argue that it’s part of the responsibility of the type checker to catch typos such as the one in the example, but languages with universal type inference just can’t do this.

Type inference can be an incredibly nice feature, and it is very tempting to just assume that “more is better” and jump whole-heartedly into languages like ML.  The problem is languages which have such universal type inference don’t provide the same safety that languages with local or no type inference can provide.  It’s just too easy to make a mistake and then not realize it until the compiler throws some (apparently) unrelated error in a completely different section of the code.  In some sense, type inference weakens the type system by no longer providing the same assurance about a block of code.  It’s important to realize where to draw the line as a language designer; to realize how far is too far, and when to step back.

The “Option” Pattern

7
Apr
2008

As I’ve gotten to know Scala better, I’ve begun to appreciate its simple power in ways which have caught me by surprise.  When I picked up the language, I was expecting to be wowed by things like type inference and a more concise syntax.  I wasn’t expecting to fall in love with Option.

The Option Monad

In case you don’t know, Option is a class in the Scala core libraries.  It is what object-oriented developers would call “a simple container”.  It simply wraps around an instance of some type as specified in its type parameter.  A simple application would be in a naive integer division function:

def div(a:Int)(b:Int):Option[Int] = if (b <= 0) None
  else if (a < b) Some(0)
  else Some(1 + div(a - b)(b).get)

Pretty straightforward stuff.  This method repeatedly subtracts the dividend by the divisor until it is strictly less than the divisor.  Of course, the fact that I wrote this as a pure function using currying, recursion and complex expressions obfuscates the meaning somewhat, but you get the drift.  What’s really interesting here is the use of Option to encapsulate the result.  Here’s how we could use this method to perform some useful(?) calculations:

div(25)(5)     // => Some(5)
div(150)(2)    // => Some(75)
div(13)(4)     // => Some(3)

Nothing earth-shattering in the mathematical realm, but it provides a useful illustration.  Each return value is wrapped in an instance of class Some, which is a subclass of Option.  This doesn’t seem very useful until we consider what happens when we try to divide values which break the algorithm:

div(13)(0)     // => None
div(25)(-5)    // => None

Instead of getting an integer result wrapped in an enclosing class, we get an instance of a totally different class which doesn’t appear to encapsulate any value at all.  None is still a subclass of Option, but unlike Some it does not represent any specific value.  In fact, it would be more accurate to say that it represents the absence of a value.  This makes a lot of sense seeing as there really is no sane value for the first computation, and the second is simply incomputable with the given algorithm.

Retrieving a value from an instance of Option can be done in one of two ways.  The first technique is demonstrated in the div method itself (calling the no-args get method).  This is nice because it’s terse, but it’s not really the preferred way of doing things.  After all, what happens if the value in question is actually an instance of None?  (the answer is: Scala throws an exception)  This really doesn’t seem all that compelling as a means of encapsulating return values.  That is why pattern matching is more frequently employed:

div(13)(0) match {
  case Some(x) => println(x)
  case None => println("Problems")
}
// => prints "Problems"
 
div(25)(5) match {
  case Some(x) => println(x)
  case None => println("Problems")
}
// => prints "5"

Pattern matching allows us to deconstruct Option values in a type-safe manner without the risk of trying to access a value which really isn’t there.  Granted, the pattern matching syntax is a bit more verbose than just calling a get polymorphically, but it’s more about the principle of the thing.  It’s easy to see how this could be quite elegant in a non-trivial example.

Compared to null

This is very similar to a common pattern in C++ and Java.  Often times a method needs to return either a value or nothing, depending on various conditions.  More importantly, some internal state may be uninitialized, so a common “default” value for this state would be null.  Consider the following lazy initialization:

public class Example {
    private String value;
 
    public String getValue() {
        if (value == null) {
             value = queryDatabase();
        }
 
        return value;
    }
}
 
// ...
Example ex = new Example();
System.out.println(ex.getValue());

Well, that’s all well and good, but there’s two problems with this code.  Number one, there’s always the potential for stray null pointer exceptions.  This is certainly less of a concern in Java than it was back in the days of C and C++, but they still can be annoying.  However, let’s just assume that we’re all good programmers and we always check potentially-null values prior to use, there’s still the problem of primitive types.  Let’s change our example just a bit to see where this causes issues:

public class Example {
    private int value;
 
    public int getValue() {
        if (value == ???) {    // er...?
             value = queryDatabase();
        }
 
        return value;
    }
}
 
// ...
Example ex = new Example();
System.out.println(ex.getValue());

If you’re following along at home, your compiler will probably complain at this point saying that what you just wrote was not valid Java.  If your compiler didn’t complain, then you have some more serious issues that need to be addressed.

Primitive values cannot be valued as null because they are true primitives (an int is actually a bona-fide integer value sitting in a register somewhere at the hardware level).  This too is a holdover from the days of C and C++, but it’s something we have to deal with.  One of the consequences of this is that there is no reasonable “non-value” for primitive types.  Many people have tried clever little tricks to get around this, but most of them lead to horrible and strange results:

public class Example {
    private Integer value = null;
 
    public int getValue() {
        // forgot to init...
 
        return value;
    }
}

This code will fail at runtime with a NullPointerException oddly originating from the return statement in getValue().  I can’t tell you how many times I’ve spent hours sifting through code I thought was perfectly safe before finally isolating a stray null value which the compiler happily attempted to autobox.

It’s worth briefly mentioning that a common “non-value” for integers is something negative, but this breaks down when you can have legitimate values which fall into that range.  In short, there’s really no silver bullet within the Java language, so we have to turn elsewhere for inspiration.

Option in Java

I was actually working on an algorithm recently which required just such a solution.  In this case, the primitive value was a boolean, so there wasn’t even a conventional non-value to jump to.  I hemmed and hawed for a while before eventually deciding to implement a simple Option monad within Java.  The rest of the API is remarkably functional for something written in Java (immutable state everywhere), so I figured that a few monadic types would feel right at home.  Here’s what I came up with:

public interface Option<T> {
    public T get();
}
 
public final class Some<T> implements Option<T> {
    private final T value;
 
    public Some(T value) {
        this.value = value;
    }
 
    public T get() {
        return value;
    }
}
 
public final class None<T> implements Option<T> {
 
    public None() {}
 
    public T get() {
        throw new UnsupportedOperationException("Cannot resolve value on None");
    }
}

The usage for this code looks like this:

public class Example {
    private Option<Boolean> value = new None<Boolean>();
 
    public boolean getValue() {
        if (value instanceof None) {
            value = queryDatabase();
        }
 
        return value.get();
    }
}

Once again, Java has demonstrated how needlessly verbose and annoying its syntax can be.  In case you were wondering, the generics are necessary on None primarily because Java has such a poor type system.  Effectively, null is an untyped value which may be assigned to any class type.  Java has no concept of a Nothing type which is a subtype of anything.  Thus, there’s no way to provide a default parameterization for None and the developer must specify.

Now this is certainly not the cleanest API we could have written and it’s definitely not a very good demonstration of how monads can be applied to Java, but it gets the job done.  If you’re interested, there’s a lot of good information out there on how do do something like this better.  The point was not to create a pure monad though, the point was to create something that solved the problem at hand.

Conclusion

Once you start thinking about structuring your code to use Option in languages which have built-in support for it, you’ll find yourself dreaming about such patterns in other, less fortunate languages.  It’s really sort of bizarre how much this little device can open your mind to new possibilities.  Take my code, and give it a try in your project.  Better yet, implement something on your own which solves the problem more elegantly!  The stodgy old Java “best practices” could use a little fresh air.

P.S. Yes, I know that the original implementation of this was actually the Maybe monad in Haskell.  I picked Option instead mainly because a) I like the name better, and b) it’s Scala, so it’s far more approachable than Haskell.

Techniques of Java UI Development

18
Feb
2008

Too often these days I see Java developers new to the psuedo-science of UI development finding themselves completely lost before they even get started.  There are a lot of misconceptions about the “best” and “easiest” way to create a professional UI in Java, and precious few resources which attempt to clear up the confusion.

In this article, I’m going to make use of the Swing framework simply because it’s more widely known.  All of the same techniques and processes apply to SWT with equal validity.  I’ll walk through the steps required to create a simple form UI in the easiest and most maintainable fashion.  I’m well aware that there are faster ways of doing this, but in my experience, this process will lead to more maintainable and less rigid UIs.

Note: These steps will obviously be different if you’re working in a team or with a designer.  The intention of this article is not to present the “be all, end all” of UI design practices, but rather to be a set of guidelines for the common-case developer.

Design

It may surprise you, but the very first step in creating a UI is design.  You have to know fairly precisely how you want the UI to look and (more importantly) behave.  This step is more than just drawing a few mockups in Illustrator.  This is sitting down and hashing out what you want the controls to do when the window is resized, if the state of any controls should be tied to that of others, whether your labels LEFT aligned or RIGHT, etc.  Often I find the easiest way to start is with a diagram:

 Diagram

This is what my diagram would look like, but it’s important to note that this isn’t a “one size fits all” style.  The point of the diagram is to give you a medium to lay out the semantics of a panel and to help you understand just what it is you have to do.  This step becomes invaluable later on as you start actually writing code.

The important thing about this diagram is that it is annotated.  Anyone can just draw a picture of what they want the UI to look like, what components to use, how they should be spaced.  The real meat of the question is not what does it look like, but how does it behave.  One of the biggest questions Java UI developer have to answer (as opposed to, say .NET developers) is how do the controls behave when the form is resized.  This is a much more complicated question than “where should the component be placed” or “how should it look”.  In essence, the question is asking “what sort of layout manager configuration do you need?”

There are two directions which need to be considered: vertical and horizontal resize.  This may not be news, but it’s something that a lot of developers (myself included) seem to forget.  The way the form scales horizontally is just as important as how it scales vertically, so it is critical that these considerations are dealt with in the design phase.  You’ll notice on my diagram that I have annotated almost every component with scaling constraints, dictating visually how the component will behave as the form changes size.  For example, all but one of the text fields scale out horizontally, but remain with a fixed height.  The one text field which does not scale horizontally is annotated so that it remains with completely fixed dimensions, both vertical and horizontal.  It’s also important to note that the City text field scales horizontally, “pushing” the State combo box as it does so.  Thus the state selection is always right aligned, the city label is left aligned, and the intervening space is filled with the city text field.  This sort of “resize mapping” (to coin a phrase) must be considered before any code is written.

You’ll notice that there is just a single annotation indicating behavior when the form resizes vertically.  This is because, like most form-based UIs, there isn’t really a good way to deal with this situation.  In this case, I just drew a line through the form where I thought I saw the most logical split and indicated annotatively that this “non-component” should be what scales vertically.  Thus the buttons remain fixed to the bottom, while the remainder of the components build down from above.  Some forms have text areas (multi-line text fields) which may scale vertically, filling this space.  Our form however has no components which logically scale in the vertical direction, thus we invent a non-component which fills the gap in our imagination.  This non-component will only be reflected in the layout constraints, we won’t have to add anything extra to the panel itself.

When drawing this diagram, note that I wasn’t afraid to make mistakes and then annotatively clarify them.  For example, I made the form to narrow to clearly express the intent of the layout.  The City and State fields take up more room than I expected.  Rather than starting from scratch, I just draw the fields as it seems most intuitive and then indicate with arrows that they should be aligned with the other text fields.  Likewise, the Line 1 and Line 2 fields should actually stretch all the way to the edge of the section.  This wasn’t clear in the diagram, so I added the –| annotation to remind myself of this fact.  Always remember that we’re not trying to make an unambiguous specification, just a reminder to ourselves.  It’s a design aid, nothing more.

The final bit of annotative goodness which needs to be observed is the “disables” marker attached to the Address checkbox and the section below it.  This marker indicates some basic UI state behavior: when the checkbox is selected, the section will be enabled; otherwise the section below (and all its components) will be disabled and no data may be entered.  Note that the annotation doesn’t say “clears” or “resets”, since we just want the section to be disabled and ignored.  Someone may disable the address section only to realize later (prior to saving) that they actually do need to enter an address.  They would likely want all of their previous changes to still be there, rather than completely lost.

Notice what we didn’t annotate here.  We didn’t clutter our design with intuitive concepts like “Save button saves the contents and closes the window”.  Rather, we left that up to our imagination and (likely) prodigious memory.  Remember that this diagram is for our use, not our manager or the other developers in our team.  If we were building a diagram for external consumption, we would have had to make an effort to be more clear.  As it is, we can trust ourselves to build a UI that makes sense according to convention.

First Steps

So we have our design diagram in hand, it’s finally time to consider some code.  It’s usually around this time that developers start thinking about what tools to use and how they can be of help.  Let me start out by saying flat-out that I am not in favor of any graphical UI design tool.  Don’t get me wrong, I think Matisse is a brilliant bit of engineering and a credit to the entire NetBeans team, but it’s not a silver bullet.  In fact, I don’t even think it’s a bullet worth firing.  I could create the code for the diagramed UI in a few minutes using Matisse, but what would the code look like?  Would it be code worth coding?

image

javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
  jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
  .addGroup(jPanel1Layout.createSequentialGroup()
    .addContainerGap()
    .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(jPanel1Layout.createSequentialGroup()
        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
          .addComponent(jLabel3)
          .addComponent(jLabel4)
          .addComponent(jLabel5))
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
          .addComponent(jTextField4, javax.swing.GroupLayout.DEFAULT_SIZE, 376, Short.MAX_VALUE)
          .addComponent(jTextField3, javax.swing.GroupLayout.DEFAULT_SIZE, 376, Short.MAX_VALUE)
          .addGroup(jPanel1Layout.createSequentialGroup()
            .addComponent(jTextField5, javax.swing.GroupLayout.DEFAULT_SIZE, 282, Short.MAX_VALUE)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(jLabel6)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, 
                 javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
      .addGroup(jPanel1Layout.createSequentialGroup()
        .addComponent(jLabel7)
        .addGap(18, 18, 18)
        .addComponent(jTextField6, javax.swing.GroupLayout.PREFERRED_SIZE, 93, 
            javax.swing.GroupLayout.PREFERRED_SIZE)))
    .addContainerGap())
);

Oh yeah, I’m looking forward to working with that code.  What’s actually worse is you can’t work with that code.  NetBeans prevents you from editing the auto-generated sections of the code.  Meaning if Matisse got it wrong (and it did a couple times during the construction of the screenshot), there’s no way for you to fix it by hand.  And even assuming you drop back to your favorite external editor to make your fix, the next time you open the file in NetBeans, your changes will be overwritten.  Matisse is a totally dominating, uncompromising beast that takes over your UI and doesn’t let go.

Honestly, this isn’t a stab at NetBeans in any way.  Matisse does a fine job auto-generating its code and it’s amazingly good at inferring layout constraints based on convention and control placement.  It’s no substitute for fine-grained manual control however.  People may argue that “UI design is a visual task”, but that’s what the design diagram is for.  I’ve worked with some fairly complex Swing UIs in my time, and let me tell you that if you don’t know how to write the code by hand, you’ll never be able to maintain it.  And if you can’t maintain your UI code, that’s going to cause tons of problems down the road.  So no quick and easy tools for our UI-making.

If we’re going to write the code by hand (and we are), then we’re going to need to decide which layout manager(s) to make use of.  This is where the diagram can be extremely helpful.  Just looking at our design suggests a grid based approach, a subpanel (for the address) and a footer panel for the buttons (probably using something like FlowLayout).  Working from the high-level down to the fine-grained details:

  1. From top down: we have a body, some empty space which stretches on resize and a footer section.  This suggests the use of BorderLayout with the “body” as the CENTER constraint and our button panel as SOUTH
  2. Button panel appears to keep the components centered, so FlowLayout would be the most appropriate
  3. Body panel seems to be a grid of two columns, one for the labels and one for the text fields.  The Address component spans both grids with a left offset of 15-20 pixels.  Below this is the address panel which spans both columns and stretches to fill.  The address panel is not set to stretch vertically, but is rather attached to the top of its cell, allowing empty space to stretch below it
  4. Address panel appears to be a grid divided into four columns.  The first two rows have text fields which span three columns.  The bottom row contains a text field which also spans three columns, but does not stretch to fill

And no, I’m not concerned with resolution independence here.  After all, if Apple doesn’t care, why should I?  :-)

This process mainly depends upon familiarity with layout managers and some experience with form layout.  I happen to know that some of the most powerful layout managers are grid based, so I try to fit most UI designs into a grid.  I also know that Swing comes with a very nice (if limited) default layout manager called BorderLayout.  Many high-level layout constructions fall into a category of problems which are trivial to manage with BorderLayout (like our button footer).  There really are a number of patterns which can be kept in mind during this layout process, but in the end it all comes down to experience.  Once you’ve built a form-based UI, the steps involved in creating another become somewhat instinctive.

We’ve already specified two of the three layout managers we will need for this UI.  All that remains is to select a grid-style manager which can accommodate both fixed and fluid constraints.  We could use GridBagLayout, but for reasons which should be obvious, I like to avoid that one.  Unfortunately, Swing doesn’t really have another grid layout which is powerful enough to accomplish our goals.  So we look outside of the core Swing API.

There are a number of third-party layout managers available, but the one I really favor is a layout manager I ported from SWT a number of years ago.  SWT’s GridLayout is basically most of the power of GridBagLayout, wrapped in a clean and intuitive API.  It’s more than sufficient for our purposes, and it won’t needlessly gum up our code with dozens of verbose constraint definitions.

Fleshing it Out

With all three layout managers chosen and most of the constraints solidified, it’s time to get our hands dirty and actually write some code.  For simplicity of example, we’re just going to put everything into a single class with a main method.  This main method will simply set the look and feel (avoiding metal) and launch the frame:

public static void main(String... args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (ClassNotFoundException e) {
            } catch (InstantiationException e) {
            } catch (IllegalAccessException e) {
            } catch (UnsupportedLookAndFeelException e) {
            }
 
            new ContactDetails().setVisible(true);
        }
    });
}

As per convention, all of our components will be created and initialized in the class constructor.  Some people are proponents of the init() or initComponents() convention, but I personally don’t see that it serves any purpose.  If you’re just calling the method from the constructor anyway, why bother?

You’ll notice that we’ve wrapped the entire launch sequence in an invokeLater()This is extremely important.  Swing (or rather, AWT) manages the entire event dispatch queue for you in separate threads.  It’s not like SWT where the event dispatch is manually, er…dispatched.  This means that the main thread is not in fact the EDT (event dispatch thread).  If we just made a call to our constructor within the main thread itself, we would be creating components and interacting with Swing in a thread other than the EDT.  Swing is pretty good at making sure that the event dispatch still works, but odd bugs can creep in around the edges.  Ever wonder why the setVisible(true) invocation sometimes blocks and doesn’t at other times?  This is usually due to the differences between an in-EDT invocation and a main thread call.  Romain Guy turned me on to this misunderstood bit of Swing usage, and I’ve been using it ever since.  Believe me when I say that you’ll save yourself a world of hurt by making sure you’re square with the EDT.

Now that we’re sure our invocations are properly wrapped, we can get started writing the UI layout code, adding the components to the frame.  Honestly, this code is more than slightly verbose and repetitious, so I’m not going to reproduce all of it.  This is just the interesting stuff:

setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(400, 265);
 
JPanel body = new JPanel(new SWTGridLayout(2, false));
getContentPane().add(body);
 
body.add(new JLabel("First Name:"));
 
JTextField firstName = new JTextField();
 
SWTGridData data = new SWTGridData();
data.grabExcessHorizontalSpace = true;
data.horizontalAlignment = SWTGridData.FILL;
body.add(firstName, data);
 
body.add(new JLabel("Last Name:"));
 
JTextField lastName = new JTextField();
 
data = new SWTGridData();
data.grabExcessHorizontalSpace = true;
data.horizontalAlignment = SWTGridData.FILL;
body.add(lastName, data);
 
JCheckBox address = new JCheckBox("Address");
 
data = new SWTGridData();
data.horizontalSpan = 2;
data.horizontalIndent = 15;
body.add(address, data);
 
JPanel addressPanel = new JPanel(new SWTGridLayout(4, false));
addressPanel.setBorder(BorderFactory.createEtchedBorder());
 
data = new SWTGridData();
data.grabExcessVerticalSpace = true;
data.horizontalAlignment = SWTGridData.FILL;
data.verticalAlignment = SWTGridData.BEGINNING;
data.horizontalSpan = 2;
body.add(addressPanel, data);

 image

Well, this isn’t quite like our diagram, but it’s close enough.  Remember that the diagram is only a guide.  It’s purpose is to focus your thought and allow you to create the layout constraints.  It’s never intended to be a hard-and-fast spec.

You’ll notice how much more readable the manually written code is than its Matisse-generated counterpart.  It may be repetitive and annoying, but it’s very readable, very maintainable.  We could actually add a little bit of abstraction here (e.g. createGridData()) to make things even more readable, but that’s overkill for this example.  Actually, not only is this code readable and maintainable by myself, but I can also check it into a shared repository and other people (potentially using different editors) can make changes to the layout and UI logic and expect them to actually work.  I’ve had nothing but bad experiences when using UI builders in a team setting, especially builders like Matisse which rely on external meta files.

One thing that is worth calling attention to is that magic number pair in the setSize() invocation.  Of course, I could have used pack(), but that rarely sizes a frame as something which looks pleasing to the eye.  I’ve found that the easiest way to get a frame which is sized nicely for most platforms is to put in some easy default width and height (say, 400×400), then once the layout is fixed, size the form by hand.  Literally run the form and resize the window until everything looks good.  Once that’s done, screenshot it and measure the width and height in Paint.  :-)  It may sound crude, but it works surprisingly well.  Of course, the size will have to change a bit, depending on which platform the app is running on, but this is easy enough to handle.  Usually I repeat the process on each platform, taking the largest width-height pair as making that the fixed standard for all platforms.

Conclusion

And there you have it, a simple Java form UI created with minimal fuss and maximum compatibility.  More importantly, the techniques presented in this article can be applied to more UIs in future, and not just forms.  All of us at some point have to build a basic Swing UI, and it’s best if we’re comfortable doing so and able to create something that’s worth keeping around.  Hopefully the concepts I have presented will be useful to you the next time you find yourself faced with a similar situation.

Java Needs Map Syntax Sugar

18
Dec
2007

I’ve never been a big fan of useless syntax sugar.  I’ve always thought that the simpler a language is syntactically, the better.  If you think about it, there’s a lot of merit to this sort of viewpoint.  I mean, which of these is easier to read?

public class Test {
    public void put(Object key, Object value) {
        // ...
    }
 
    public Object get(Object key) {
        // ...
    }
}
 
// ...
Test test = new Test();
test.put(String.class, "blah");
test.put(StringBuilder.class, "blahblah");
 
String value = (String) test.get(StringBuilder.class);

Or this?

public class Test<K, V> {
    public void put(K key, V value) {
        // ...
    }
 
    public V get(K key) {
        // ...
    }
}
 
// ...
Test<Class<? extends CharSequence>, String> test = 
        new Test<Class<? extends CharSequence>, String>();
test.put(String.class, "blah");
test.put(StringBuilder.class, "blahblah");
 
String value = test.get(StringBuilder.class);

The only thing that has different between the examples is one makes use of generics, the other doesn’t.  The top example makes use of a cast, the bottom avoids this.  The lower example also has some trivial compile-time checking, but that’s about it. 

So what have we done here?  We complicated a trivial example with 50-100 extra, cryptic characters and managed to avoid a single, 9-character cast.  Not really an improvement.  I’ll grant you that generics are usually very beneficial, and I won’t deny that I like them and make use of them myself, but the point of the example is unchanged: extra “beneficial” syntax constructs are not always a good thing.

With all this said, I still have to admit that I’m (grudgingly) in favor of certain syntax additions.  Closures for example are probably the absolute best proposal for Java 7 I’ve heard yet.  Obviously we can quibble over the syntax, but I think the construct itself is a very valuable one.  I’m also (again grudgingly) in favor of another syntax sugar having to do with method parameters.

Many methods these days take a Map as a parameter.  It’s a fairly common thing to pass values that way.  JDBC is a good example (well, actually it’s a Properties instance).  ActiveObjects has a method to create an entity, passing a map of field => value pairs to be set on the INSERT.  Often times, such methods are an enormous pain to call.  Example:

Map<String, Object> params = new HashMap<String, Object>();
params.put("firstName", "Daniel");
params.put("lastName", "Spiewak");
Person person = em.create(Person.class, params);

Alright, not horrible. But imagine you had several dozen values to pass. It’s not that uncommon for such a situation to arise, and right now it always leads to vast quantities of syntax cruft.

Of course, there is a shortcut notation, but it’s almost as verbose and virtually unknown (which makes it a bad choice due to readability concerns):

Person person = em.create(Person.class, new HashMap<String, Object>() {{
    put("firstName", "Daniel");
    put("lastName", "Daniel");
}});

What this is actually doing is declaring a constructor for an anonymous inner class extending HashMap.  It’s not too bad in terms of syntax, but very few Java developers are aware of this construct, thus it should probably be avoided.

Now if we consider the corresponding syntax in a language like Ruby, things fall out beautifully (here using symbols instead of Strings for the keys):

person = em.create(Person, :firstName => "Daniel", :lastName => "Spiewak")

Obviously I’m taking a bit of artistic license with the API, but you get my drift.  This code is so much cleaner because Ruby has a syntax construct which allows the implicit creation of Hash objects (the Ruby equivalent of Map) as required within the method invocation.  The above syntax is equivalent to the following:

params = Hash.new
params[:firstName] = "Daniel"
params[:lastName] = "Spiewak"
person = em.create(Person, params)

So nothing too complex, Ruby just makes it cleaner.  Most scripting languages actually have a similar construct, for example Groovy allows for the key:value syntax in method parameters, dynamically creating a Java Map as necessary.

I think Java should add a similar syntax.  There are enough cases where such a construct would greatly simplify the code in question.  We wouldn’t even need to add symbol literals to the language, we could just use standard Java types.  Perhaps something like the following is in order:

Person person = em.create(Person.class, "firstName":"daniel", "lastName":"Spiewak");

Completely unobtrusive, easy to read, and even more compact than the Ruby version.  The syntax is familiar to anyone using Groovy (more and more these days) and it doesn’t require the introduction of a new keyword or clumsy over-riding construct.  It’s type-checked, so compile-time safe, and totally backwards compatible (you could use this syntax on legacy APIs without modification).

So the question: is it worth it?  Since Java was open sourced, we’ve been seeing more and more efforts like KSL (the Kitchen Sink Language).  People have been hearing so many new language proposals that there’s beginning to be an anti-change backlash.  Many of the developers I respect are more and more of the opinion that Java should remain the way it is.  Those who want all the fancy language additions should use Scala.

In a lot of ways, I agree with them.  In my opinion, Java’s too bulky and inconsistent in its syntax already, but I think this might just be one area where an exception could be made.  Perhaps this construct is simple enough, unobtrusive enough and ubiquitously useful enough to be worth the effort of putting it into the language.

In Search of a Better Build System

26
Nov
2007

There’s a consistent problem with developing applications of any reasonable size, a problem which has dated back even before the early days of C.  The problem is that any application of significance will be composed of several source files.  In fact, reasonable applications are often found to be composed of thousands if not hundreds of thousands of files.  Back in the day, it was felt (for some reason which escapes me) that it would be poor practice to type “gcc -Wall -o filename.o filename.cpp” several thousand times every time the app needed to be recompiled.

So from very early on, developers have been writing tools to aid in the build process.  Some of these tools (most of them) were somewhat ad hoc and specialized.  The most common example which springs to mind is a simple script, which handles the compilation:

#!/bin/sh
 
for f in *.c; do
  name=`echo $f | sed 's/.c//'`
  gcc -Wall -o ${name}.o ${name}.c
done

The limitations of such an approach should be obvious.  For one thing, you can only use this script on a single directory which contains all source files.  This is very rarely the case.  More importantly, there is no linking or dependency checking taking place.  This means that with the exception of very simple applications, this script will outright fail every time.  Of course, you could modify the script extensively to hard-code the dependency information, check for file modification, etc.  However, this would be a long, dull process which would have to be repeated for every application you write.  Not a very productive way to spend your time.

And so was born make.  Make has a number of advantages over the hand-scripted method.  It allows for (fairly) easy dependency specification, it will only compile modified files, it lets you ensure everything happens in the proper order, it’s more maintainable, etc.  However at its core, Make is almost exactly a wrapper around the hand-script method.  As such, it suffers from many of the same limitations, such as a cryptic syntax and a dependence on the underlying shell.  Make is a far cry from hand scripting everything, but it’s hardly the silver bullet developers were looking for.

So as the years went by, more and more solutions were devised, though few of them caught on to the extent that Make had.  To this day, Make is still the de facto standard for C and C++ build systems.  Its dominance is so pervasive that I have even found Java applications which are built using Make, though thankfully these are far and few between.  With Java on the scene, attention turned to a new effort which attempted to unseat Make as the reigning champion of the build tools: Ant.

Ant based its syntax on XML, breaking completely with Make’s bash roots and focusing on the task rather than the dependency.  Because of this clean break, and due to the fact that the Ant interpreter itself is written in Java, Ant is entirely platform agnostic.  An Ant build script written for a Java project can be run on any platform, anywhere (as long as Java is installed).  This immediately gave it a huge boost over Make as it finally enabled developers on platforms such as Windows and MacOS 9 (and earlier), platforms without the advantages afforded by a real shell.  Ant’s rise to dominance in the field of Java build systems was so rapid and so completely unchallenged that it still remains the “proper” way to build a Java application.  Every Java developer has Ant installed, and as such it has become something of a lingua franca in build script land.

Unfortunately Ant, like Make suffers from a number of shortcomings.  Its XML syntax for one, while instantly recognizable and familiar to 99% of developers on this planet, poses problems with verbosity and expressiveness.  For example, Ant doesn’t provide any real mechanism for variables, bona fide procedures or any way to execute arbitrary code without a clean break into Java (a custom Ant Task).  While this tends to keep build scripts somewhat uniform and easily understandable (when you’ve seen one build.xml, you’ve seen them all), it also forms a crippling limitation in many ways.  I’ve used Ant a lot in my time, and let me tell you it can be a real pain.  For simple builds (javac a bunch of source files, copy one or two resources, zip the result, etc) it’s quite sufficient, but headaches set in when dealing with anything complex like chained builds, subprojects or library dependency management.  You can make it work, but it’s not pretty.

The Maven project was started to try to address some of these problems (among other things).  Maven provides full-stack dependancy management (even resolving and downloading third-party libraries), build management, conventions enforcement, IDE interop and so on.  A number of people would say that Ant is completely superceded by Maven, and that Maven is the only way to go for any new Java project.  Unfortunately, like so many successful Java projects of its day (a few examples Spring to mind), Maven refused to maintain its focus.  Instead of being an incredibly simple build system and dependency management tool, Maven has tried to branch out and become the all-encompassing tool to solve everything.  I know I haven’t even scratched the surface of its capabilities in my limited exposure, but I can say that I’ve seen enough.  Maven is amazing, but way way to invasive for my tastes.  It has a knack of making the simple things cryptic, the hard things harder and the complex things impossible.  (by impossible I mean without resorting to hackery like invoking Ant from within Maven or calling out to a shell script)  Now I realize flame wars have been fought on this very subject, but I have to conclude that Maven is just too much and too overwhelming for easy use (and hence, wide adoption).

Fortunately for me, the rise of dynamic languages has brought about some wider options.  Ruby in particular has become a favorite for many different build tool projects (Rake, Raven, etc).  Most interesting is the effort underway to provide a “non-sucky Maven”.  The Buildr project, currently in incubation at Apache, is basically seeking to be a build system which enables trivial application of the most common case (builds and dependencies), as well as the flexibility of a Turing-complete language (Ruby) to make possible just about any build task, no matter how esoteric.

Buildr’s promise is indeed alluring, and at first glance it seems to deliver.  The DSL syntax of the build file is intuitive and easy to grasp.  With this it bundles the full power of Maven, allowing it to be a drop-in replacement for any pre-existing Maven project.  Well, almost.  Buildr doesn’t allow for things like dependency checkout from a source code repository.  It also retains one of Maven’s biggest failings in that it unduly enforces a rigid directory structure.  While it is possible to override this restriction, Buildr’s documentation isn’t exactly clear on how, and to be honest I still haven’t figured out how to get some things working.  Buildr is promising, but not perfect.

Another flaw suffered by all of the new, “avant garde” build tools is that not all of them can be expected on every developer’s machine.  Back in the days of Make and Ant, every developer knew that every other developer could handle a build.xml file and use it to get a fully functional build out the other end.  Unfortunately, while Maven has made tremendous strides in popularity, it is still no where near as ubiquitous as Ant.  Buildr is even less common, additionally requiring the separate installation of a full Ruby runtime, as well as the “buildr” gem.  These considerations are less significant for a small commercial product, where all of the developers are in close contact and outside interference is rare.  However, for the open-source project, standardization in the required tools is critical, otherwise new developers would have no way to contribute.

Unfortunately it’s a bit of a Catch-22.  Even assuming Buildr manages to make good on its promise of being “a build system that doesn’t suck”, it has to gain in popularity before it will be accepted as the de facto standard for Java project builds.  But to gain popularity, Buildr must be accepted by the community.  It’s a tightly knit, closed circle driven by managers remaining content with “the way it’s always been done” and developers refusing to chance the success of their project on the hope that all parties concerned will also show forward thinking in their tool set.  I really don’t envy the Buildr project leads in their task to promote their tool.

So where does this leave me?  Practically speaking, I’m still going to stick with Ant.  Buildr may be interesting, and Maven may be powerful, but neither is the standard yet.  Perhaps even more importantly: I’m lazy.  I know Ant.  I know it very well and I would have to see some pretty clear benefits (and an easy introductory road) to switch my build system of choice.  Right now, I don’t see either of those.  Maven is infamous for having a very steep learning curve.  And as I mentioned before, Buildr’s documentation leaves something to be desired.

I want to help usher in the next era of Java development as much as the next guy.  But I’m not willing to sacrifice the now for the sake of a future which may take a totally different form when it arrives.  So I will (reluctantly) stick with my old standby.  Perhaps someday I’ll come across a build tool which really impresses me enough to make me switch.  Until then you can continue to listen to me whine and complain about the difficulties of whipping Ant into shape.  How lucky for both of us.  :-S