Tuesday, November 30, 2010

Writing Java effectively in a manually compiled DSL

Introduction

When I write Java, I write in a DSL similar to Java which is compiled to Java manually using the UI-actions of the Java-plugin for eclipse. If I ever change IDE, I have to learn a new DSL from scratch. Let me explain:

For me, the Java language and the Eclipse IDE with the Java plugin forms a new language. The language I program in _is_ Java, but not if you look at my keystrokes. The Autocompletion, Refactorings, Quick Helps and other automated source code changing tools provided by Eclipse (henceforth Tools) allow me to program at a much higher level than pure Java. Three years of experience with Java/Eclipse allows me to leverage the Tools a lot.

I almost never declare anything (variables, parameters, fields, methods, constructors, classes)! Instead, I rely on the Tools to do that for me. The lack of declaration will be the focus of the examples in this post.

UI-actions

In the following examples I will be using the UI-actions of Eclipse a lot, they will be mentioned by the name you see in:
Windows -> Preferences -> General -> Keys.
I will always be using keyboard shortcuts to invoke them. A UI-action invocation will be denoted in brackets: e.g. [Quick Fix] A sequence of UI-action invocations will be comma separated in a pair of brackets: e.g. [Next, Quick Fix].

The cursor position will be denoted by _.

Specific keyboard key presses will be denoted by capital letters in braces: e.g. {ENTER}.

Example 1

Scenario: need to invoke the method "Qux foo(Bar, Baz)", and store the result in a local variable.

I type in "foo;" and move the cursor one place to the left:
foo_;
[Content Assist] will immediatly give me:
foo(bar, baz);
Eclipse will now complain about the missing variables "bar" and "baz". I then invoke: [Quick Fix, {ENTER}, Next, Quick Fix, {ENTER}]. Both times Quick Fix will suggest to introduce the variables "bar" and "baz", I let them be introduced. This will automatically import the right version of Bar and Baz.
Bar bar;
Baz baz;
foo(bar, baz);
Eclipse will still complain, this time about uninitialized variables, we need to [Save] in order to write our changes to the underlying AST, which all the UI-actions operate on. Once this is done we use: [Quick Fix, {ENTER}, Next, Quick Fix, {ENTER}, {ENTER}] to initialize the variables. Focus will be given to the initialized value, allowing an immediate definition of the value, but I prefer to finish the task at hand first: invoking foo.
Bar bar = null;
Baz baz = null;
foo(bar, baz);
Finally the return value of foo should be stored in a variable, and as we still are on the line of the invocation: [Quick Assist - Assign to local variable, {ENTER}] will do just that.
Bar bar = null;
Baz baz = null;
Qux foo = foo(bar, baz);_

Comparison

This is definitely not a complete trick you should try to remember. It consists of a lot of small steps, and a lot of experience with the Tools of Eclipse. But it is certainly worth trying to understand the steps involved in the process. For me it is worth it for two reasons: I type less, and I keep focus at the task at hand instead of being bugged down in details about declaring a variable of the right type.

As a meassure of the "less typing" proposition, let's count the number of keystrokes needed to write in a completely naive way (without even using autocompletion or autoformatting) and compare that with the steps just described.

Naive way

Bar bar = null;
Baz baz = null;
Qux foo = foo(bar, baz);_
Contains 56 characters including whitespace, thus 56 key presses. For simplicity, I assume that the Bar, Baz and Qux types are imported already.

My way

Initial typing:
foo_;
contains 4 characters and one cursor move: 5 key presses. The rest: [Content Assist], [Quick Fix, {ENTER}, Next, Quick Fix, FNTER}], [Save], [Quick Fix, {ENTER}, Next, Quick Fix, {ENTER}, {ENTER}], [Quick Assist - Assign to local variable, {ENTER}].

Now, my keyboard bindings to UI-actions are very customized, so you have to trust me here. I do not consider modifiers (ctrl, alt) a key press, as they are done at the same time as the eeypress they modify, and as they are done by my thumbs which rests above the modifier anyway.
UI-actionKey pressesTimes usedToal key pressses
"foo_;"515
[Content Assist]111
[Quick Fix]144
{Enter}166
[Save]111
[Next]122
[Quick Assist - ...]212
21
21 key presses versus 56 key presses, that's a huge saving!

Example 2

Extending the previous example, I present one more example: I want to instantiate an object of a subtype of Baz, which depends on a Bar object.
Bar bar = null;
Baz baz = null;
Qux foo = foo(bar, baz);_
I start by trying to instantiate a subtype of Baz instead of the null value:
Bar bar = null;
Baz baz = new BazSubtype(bar)_;
Qux foo = foo(bar, baz);
Eclipse will complain about the missing type BazSubtype. We generate it: [Quick Fix, {ENTER}, {ENTER}]
public class BazSubtype implements Baz {
}
Our focus is now the newly generated class BazSubtype which implements Baz, but we need to implement the constructor: we go back to the previous editor and make Eclipse generate the constructor for us: [Next Editor, Quick Fix, {Arrow Down}, {Enter}]
public class BazSubtype implements Baz {
  public BazSubtype(Bar bar) {
    // TODO Auto-generated constructor stub
  }
}
Eclipse complain about the missing type Bar, as it wasn't imported automatically (which is odd!) so we import it: [Organize Imports].

We want to assign the parameter to a field. We move the focus to the parameter and generate the field and an assignment: [Quick Assist - Assign parameter to field]
public class BazSubtype implements Baz {
  private Bar bar;
  public BazSubtype(Bar bar) {
    this.bar = bar;
    // TODO Auto-generated constructor stub
  }
}
The "// TODO " should now be removed, and the field should be used for something, such as [Generate getters and setters], [Generate hashCode() and equals()] or perhaps some custom code.

If we save this class, and go back to the class we started in, we should have completed the task. [Save, Next Editor, Save]

Apart from navigating to the "bar" parameter and typing the initial constructor invocation, 14 keystrokes are used to complete the task. It is left as an excercise for the reader to compare this to a more manual way (not necessarily completely naive, like before).

Final remarks

Now it could be claimed that these examples are contrived (they are). But I assure you that this heavy use of UI-actions (and proper bindings for them!!) really boosts my productivity when coding Java.

This way of coding removes a lot of the boilerplate code which is often associated with Java. I hardly ever type the name of the Types in my programs, thus keystroke-wise my Java DSL becomes a language with stronger type inference than regular Java.

In general, the [Next, Quick Fix, {Enter}] combination is incredible effective, but it requires that you know _what_ Quick Fix will suggest as the first action to perform - this requires usage experience. Using [Next, Quick Fix] followed by an inspection of the suggestions is the way to get that experience.

It should be noted that [Quick Fix] isn't the only UI-action you should learn, but it is the one you can use most often. Others, such as [Generate getters and setters], [Generate hashCode() and equals()] generate a lot of (bug free!) boiler plate, but are not used as often. You should look through the list of available actions in the categories Quick Assist, Refactor and Source, you _will_ be surprised about the amount of usable actions!

Thursday, November 26, 2009

Emacs screencast: rectangles

I've just made a screencast about using rectangles in Emacs, so I figured I should explain how I made it.

I made it with ScreencastMode for Emacs - which I happen to be the author of.
With it, you can create a screencast by writing the manuscript for the screencast in a mix of natural language and elisp. The playing of the screencast itself is handled by Emacs - by stepping through the manuscript at pace equivalent to as if a human had done them. The video-recording at youtube is done using this.
The mode supplies utility functions for the producer such as pauses, slow typing, and blinking regions.

A simple example screencast file looks like:
(require 'screencast)

(screencast 
  '(
    "This is the message-buffer."
    (i "This is the command-buffer.")n
    "I will now show you how to save the command-buffer:"
    (save-buffer)
  )
"sample"
1.1
)
      
Which results in the following buffer output when the screencast has been played to the end.

Notice how the message-buffer contains the description of the commands done on the command-buffer. That is the way it works: the message-buffer describes what is going on in the command-buffer

More screencast sources can be found here.

Some critical questions has been asked about ScreencastMode, here are my attempts at answering them:
  • Why not read the info pages, which contains more details?
    • some people finds it easier to watch movies than reading static text.
    • screencast-mode displays the capabilities of a mode, instead of describing them.
    • those who just need to know how to use a mode doesn't need all the details of the info-page.
  • If videos are superior, why not just create a regular video?
    • a video is static, it's hard to change it if you discover an error - you'll have to do it in one take unless you got some video editing software.
    • the screencast sources can be edited by others, inviting collaboration (also it's a lot smaller size-wise)
    • the screencast will tell the user if his Emacs is configured right to use the feature it explains

Wednesday, November 25, 2009

Writing blog posts with Emacs

I'll be writing all my blog posts with Emacs (using html-mode), as Emacs is my favorite editor. But a big part of why I use Emacs for this, when a fancy web editor already is present in my browser, is the Firefox plug-in "It's All Text!". This simple plug-in allows me to pop into Emacs from any text box in Firefox, edit the content of the text box as if it was a normal file, save it, pop back to Firefox and watch the content of the text box change to what I just wrote in Emacs! The only setup required was to point "It's All Text!" to my editor program, and setup a shortcut to activate it - and voila: seamless integration between Firefox and Emacs. As a nice side effect, the texts are saved locally, thus I don't have to worry about a browser failure which usually would require me to write the text from scratch once more.

Before switching to "It's All Text!", I used Firemacs. Firemacs provides Emacs like bindings/shortcuts to the text boxes of Firefox - but when it comes to editing longer texts (such as this), then a fully fledged Emacs is superior to a few bindings.

Hello world!

Being a computer science student, I had to make this my first blog entry. The future content of this blog will be about being productive using the right tools. You can be guaranteed to see Emacs, Eclipse and Zsh mentioned often. Posts about shortcuts and general keyboard usage will also be present.