A simplified syntax for using Runnable
and other closures in Java

Sun bug ID 6433012

Submit Date 01-JUN-2006
(The argument presented here is significantly enhanced over the bug report.)

Greatly simplify creating a Runnable, Callable, or other closure
by using the ‘do’ keyword in a new way that fits in with Java syntax.


Here is some example code. The commented-out lines show the proposed syntax. More about that after the example.

All examples on this page compile and run in 1.5. Download them here.

import java.util.concurrent.Callable;

// See http://Yost.com/computers/java/closures
class EasyRunnable {

  public static void main(String[] args) throws Exception {
//  new EasyRunnable().proposal();
    new EasyRunnable().worksLikeThis();
  }

  int bar = 0;
  String baz = " so far.";

  static void proposal() throws Exception {
    String foo = "Objections: ";
//  Runnable r = do(foo, bar) { System.out.println(foo + bar + baz); };
//  r.run();
//  Callable<String> c = do(foo, bar) { return foo + bar + baz; };
//  System.out.println(c.call());
  }

  void worksLikeThis() throws Exception {
    String foo = "Objections: ";
    Runnable r = new $java_lang_Runnable1(foo, bar);
    r.run();
    Callable<String> c = new $java_util_concurrent_Callable1(foo, bar);
    System.out.println(c.call());
  }

  //----------------------------------------------------------------------------
  // Code from here to end of class is generated by the compiler

  private class $java_lang_Runnable1 implements Runnable {
    $java_lang_Runnable1(String foo, int bar) {
      this.foo = foo;
      this.bar = bar;
    }

    private final String foo;
    private final int bar;

    public void run() {
      System.out.println(foo + bar + baz);
    }
  }

  private class $java_util_concurrent_Callable1 implements Callable<String> {
    $java_util_concurrent_Callable1(String foo, int bar) {
      this.foo = foo;
      this.bar = bar;
    }

    private final String foo;
    private final int bar;

    public String call() {
      return foo + bar + baz;
    }
  }
}

First, what does this code actually do? It makes a Runnable instance then runs it. The instance contains snapshots of the foo local variable and the bar field as of the time of the creation of the Runnable (because they were passed to the constructor). The baz field of the EasyRunnable instance is not snapshotted, so the Runnable will use baz’s current value at runtime.

The proposed syntax vastly simplifies the syntax for creating a Runnable, simplifying many lines of boilerplate down to just one line of meat.

For simplicity, the above discussion has mentioned only Runnable, but the example shows that the same syntax can also be used for Callable. The compiler decides whether to create a new Runnable or a new Callable simply by the presence of a return statement with an argument. (See The trouble with Callable below.)


Usage beyond Runnable and Callable

Runnable is an easy target for such a syntax proposal because Runnable has only a single, no-arg method (and Runnable is in the java.lang package).

But can we expand this syntax proposal to encompass any arbitrary class or interface? Yes!

Consider:

Runnable r = do(foo, bar)                { System.out.println(foo + bar + baz); }

Runnable is the default class/interface for closures, and it has only one method. If we want to be explicit, we can say this:

Runnable r = do(foo, bar) Runnable.run() { System.out.println(foo + bar + baz); }

If a class or interface has only one no-arg method (as does Runnable) the method need not be named. (The same goes for an abstract class that has only one abstract, no-arg method.) So we can say this:

Runnable r = do(foo, bar) Runnable       { System.out.println(foo + bar + baz); }

Now we have some wiggle room to use the closure syntax with other classes or interfaces. Here is some example code:

import javax.swing.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.*;

// See http://Yost.com/computers/java/closures
class EasyListener {

  public static void main(String[] args) throws Exception {
    EasyListener instance = new EasyListener();
//  instance.proposal();
    instance.worksLikeThis();
  }

  EasyListener() {
    textField = new JTextField();
    textField.setText("Type the Return key.");
    JFrame frame = new JFrame();
    frame.add(textField);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().setPreferredSize(new Dimension(300, 40));
    frame.pack();
    frame.setVisible(true);
  }

  static final String msg = "Event: ";
  JTextField textField;

//static void proposal() throws Exception {
//  f.addActionListener(do(msg) ActionListener.actionPerformed(ActionEvent e) { System.out.println(e); });
//  f.addKeyListener   (do()    KeyListener.keyTyped(KeyEvent e)              { System.out.println(e); });
//}

  void worksLikeThis() throws Exception {
    textField.addActionListener(new $java_awt_event_ActionListener1(msg));
    textField.addKeyListener   (new $java_awt_event_KeyListener1()      );
  }

  //----------------------------------------------------------------------------
  // Code from here to end of class is generated by the compiler

  private class $java_awt_event_ActionListener1 implements ActionListener {

    public $java_awt_event_ActionListener1(String msg) {
      this.msg = msg;
    }

    private final String msg;

    public void actionPerformed(ActionEvent e) {
      System.out.println(msg + "ActionEvent");
    }
  }

  private class $java_awt_event_KeyListener1 implements KeyListener {
    public void keyPressed(KeyEvent e) {}
    public void keyReleased(KeyEvent e) {}

    public void keyTyped(KeyEvent e) {
      System.out.println("KeyEvent");
    }
  }
}

Again, we get a massive reduction in clutter, especially when implementing an interface that has multiple methods.

What about method arguments? You declare the method’s arguments explicitly, choosing your own names for argument variables (as an API cannot specify method argument names):

f.addKeyListener(do() KeyListener.keyTyped(KeyEvent evt) { System.out.println(evt); });


A more formal discussion


Closure:
        do ( ArgumentListopt ) ClosureMethodDeclaratoropt  Block

ClosureMethodDeclarator:
        ClassOrInterfaceType
        ClassOrInterfaceType . MethodName ( FormalParameterListopt )

means

Here are some points to note:


Java vs other languages with closures

In answer to Martin Fowler’s page about the lack of closures in Java and other languages, I offer the following rendering of his closure example code using the proposal presented here.

The example also illustrates how a class lacking a no-arg constructor might be subclassed by the syntax. The idea is this: if the class has only a single constructor and that constructor requres arguments, then the first arguments in the do() argument list must be objects that are type-compatible with the constructor’s arguments (and will be passed to super()). Additional do() arguments are handled as if the class had only a single, no-arg constructor.

It gets tricky if the class to be subclassed has more than one constructor. I leave it as an exercise for language lawyers to figure out how far the specification can go toward allowing usage with classes having constructor arguments and/or having multiple constructors.

import java.util.Collection;
import java.util.ArrayList;
import java.util.LinkedList;

// See http://Yost.com/computers/java/closures
// See http://www.martinfowler.com/bliki/Closure.html
public class FowlerDemo {

  public static void main(String[] args) throws Exception {
    emps = new ArrayList<Employee>();
    Employee john = new Employee("john", true, 200);
    emps.add(john);
    emps.add(new Employee("joe",  false, 40));

    System.out.println(managers(emps));

    System.out.println(highPaid(emps));

    Selector<Employee> highPaid = paidMore(150);
    System.out.println(highPaid.select(john));
  }

  static Collection<Employee> emps;

  static Collection<Employee> managers(Collection<? extends Employee> empsArg) {
//  return do(empsArg) Selector<Employee>.select(Employee item) { return item.isManager; }.selectAll();
    return new $Selector1<Employee>(empsArg).selectAll(); // Works like this
  }

  static Collection<Employee> highPaid(Collection<? extends Employee> empsArg) {
    int threshold = 150;
//  return do(empsArg, threshold) Selector<Employee>.select(Employee item) { return item.salary < threshold; }.selectAll();
    return new $Selector2<Employee>(empsArg, threshold).selectAll(); // Works like this
  }

  static Selector<Employee> paidMore(int amount) {
//  return do(emps, amount) Selector<Employee>.select(Employee item) { return item.salary > amount; };
    return new $Selector3<Employee>(emps, amount); // Works like this
  }

  //----------------------------------------------------------------------------
  // Code from here to end of class is generated by the compiler

  private static class $Selector1<T> extends Selector<Employee> {

    public $Selector1(Collection<? extends Employee> c) {
      super(c);
    }

    public boolean select(Employee item) {
      return item.isManager;
    }
  }

  private static class $Selector2<T> extends Selector<Employee> {

    public $Selector2(Collection<? extends Employee> c, int threshold) {
      super(c);
      this.threshold = threshold;
    }

    private final int threshold;

    public boolean select(Employee item) {
      return item.salary < threshold;
    }
  }

  private static class $Selector3<T> extends Selector<Employee> {

    public $Selector3(Collection<? extends Employee> c, int amount) {
      super(c);
      this.amount = amount;
    }

    private final int amount;

    public boolean select(Employee item) {
      return item.salary > amount;
    }
  }
}

class Employee {

  Employee(String name, boolean isManager, int salary) {
    this.name = name;
    this.isManager = isManager;
    this.salary = salary;
  }

  final String  name;
  final boolean isManager;
  final int     salary;

  public String toString() { return name; }
}

//==============================================================================
// Probable candidates for java.util

abstract class Selector<T> {

  public Selector(Collection<? extends T> c) {
    this.c = c;
  }

  private final Collection<? extends T> c;

  public abstract boolean select(T item);

  public Collection<T> selectAll() {
    return Selections.selectAll(c, this);
  }

  public Collection<T> selectAll(Collection<T> result) {
    return Selections.selectAll(c, this, result);
  }
}

class Selections {

  private Selections() {}

  public static <T> Collection<T> selectAll(Collection<? extends T> c,
                                            Selector<T> selector) {
    Collection<T> result = new LinkedList<T>();
    return selectAll(c, selector, result);
  }

  public static <T> Collection<T> selectAll(Collection<? extends T> c,
                                            Selector<T> selector,
                                            Collection<T> result) {
    for (T obj : c) {
      if (selector.select(obj)) {
        result.add(obj);
      }
    }
    return result;
  }
}

The trouble with with Callable

Callable is not in the java.lang package. It should have been, of course. But that little mistake shouldn’t ruin Callable’s chances of participating in this proposal on equal footing with Runnable.


http://Yost.com/computers/java/closures/index.html - this page
2006-06-12 Created
2006-06-13 Added Selector example
2006-06-14 Refactored Selector to Selector and Selections
2006-06-14 Added FowlerDemo
2006-07-07 Clarified, FowlerDemo now stands alone
2006-07-17 Minor edits
2006-07-18 Added main to EasyListener; added missing import to FowlerDemo; added download
2006-07-19 Revamped the presentation, including lots of rationale
2006-07-20 Added JLS sketch and volatile idea
2006-07-23 Added import suggestion