Tuesday, August 19, 2008

Modifier 'for'

Modifier 'for'

Method modifier 'for' enables us to declare and call "loop-like" methods.

  static for void eachEntry(int[] values, { int ==> void } block) {
    for (int p : values) {
      block.invoke(p);
    }
  }
  
  public static void main(String[] args) {
    int[] v = { 2, 3, 5, 7, 11 };
    for eachEntry(int i : v) {
      System.out.println(i);
      if (i > 3) {
        break;
      }
    }
  }
  

For example, we can declare a method that iterates through a map:

  static for <K, V> void eachMapEntry(Map<K, V> dict, 
      { K, V ==> void } block) {
    for (Map.Entry<K, V> entry : dict.entrySet()) {
      block.invoke(entry.getKey(), entry.getValue());
    }
  }
  
  public static void main(String[] args) {
    Map<String, String> dict = new HashMap<String, String>();
    ...
    for eachMapEntry(String k, String v : dict) {
      System.out.println(k + ": " + v);
    }
  }
  

Nonlocal transfer

Nonlocal transfer

In unrestricted closures, we can use the break, continue, and return statements.

  for (int i = 0; i < 5; i++) {
    System.out.println(i);
    if (i == 2) { ==> break; }.invoke();
  }
  

These statements are always lexically bound, i.e. they are bound in the context in which the closure is declared (as opposite to invoked). So, the following code will print numbers from <1,10> that are not multiples of 3.

  static void m(int i, { int => boolean } cond, { ==> void } block) {
    if (cond.invoke(i)) {
      block.invoke();
    }
  }
  
  public static void main(String[] args) {
    for (int i = 1; i < 10; i++) {
      // continue is bound to the for loop
      m(i, { int i => i % 3 == 0 }, { ==> continue; });
      System.out.println(i);
    }
  }
  

The return statement returns from the bound method.

  static int m1() {
    // return here means "return from m1"
    m2({ double d ==> if (d < 0.5) return 1; });
    return 0;
  }
  
  static void m2({ double ==> void } p) {
    // the closure invocation can cause return from m1
    p.invoke(Math.random());
  }
  

If the bound method is not active at the time when we call the closure with the return statement, we will get the UnmatchedTransfer exception. For example:

  // any type can be used as the return type of p in this
  // example because the closure always returns earlier
  // so, p can be declared also as static { ==> int } p;
  static { ==> boolean } p;
  
  static int m1() {
    p = { ==> return 1; };
    return 0;
  }
  
  public static void main(String[] args) {
    System.out.println(m1());
    System.out.println(p.invoke());
  }
  

Unrestricted closures are useful when declaring "statement-like" methods.

  static void withLock(Lock lock, { ==> void } block) {
    try {
      lock.lock();
      block.invoke();
    } finally {
      lock.unlock();
    }
  }
  
  public static void main(String[] args) {
    Lock guard = new ReentrantLock();
    double d = Math.random();
    withLock(guard) {
      if (d < 0.5) {
        return;
      }
      ...
    }
  }
  

Saturday, March 29, 2008

Method references (Implementation Issue)

Method references (Implementation Issue)

Each method reference is transformed to a closure:

  // Math#sqrt(double) will be transformed to { double d => Math.sqrt(d) }
  { double => double } sqrt = Math#sqrt(double);
  

Instance method references are transformed in a similar way.

  Circle c = new Circle();
  { => void } p = c#draw();  // the same as { => c.draw(); }
  
  { Circle => void } p = Circle#draw();  // { Circle c => c.draw(); }
  

Let us have a look at another example. We declare class Box:

  public class Box<T> {
    T v;
    public Box(T v) {
      this.v = v;
    }
    public T getValue() {
      return v;
    }
    public void print() {
      System.out.println("Box: " + v);
    }
  }
  

and refer to the print method:

  // Box#print() will be transformed to { Box<Integer> box => box.print(); }
  { Box<Integer> => void } p = Box#print();
  

Reference to a generic method will be replaced by a closure as follows:

  public class Generic {
    public static <T> Box<T> copy(Box<T> b) {
        return new Box<T>(b.getValue());
    }
  }
  
  // Generic#copy(Box<Integer>) will be transformed to 
  // { Box<Integer> box => Generic.copy(box) }
  { Box<Integer> => Box<Integer> } boxCopy = Generic#copy(Box<Integer>);
  

I do not want closures in Java because they are not simple.
This argument is wrong. We should always weigh all pros and cons. Closures are not simple. But is software development in Java simple? What should I know to be capable to develop software in Java? Knowledge of the Java programming language is clearly not enough. One should also know some Java technologies and frameworks. And are they simple? Are JPA, EJB, JAX-WS, Hibernate, or Spring (to name a few) simple? Apparently no, so it does not make sense to reject closures just for this reason.

Thursday, March 20, 2008

Method References (version 2008-03-17)

Method references (version 2008-03-17)

The compiler prototype (available at http://www.javac.info) comes with method references (also known as eta expansion). The method references are written as follows: ClassName # methodName ( listOfArgumentTypes ).

A method reference can be assigned to a function variable:

  { String => int } parseInt = Integer#parseInt(String);
  int x = parseInt.invoke("42");
  

We can use the covariant return:

  // Integer.valueOf() returns Integer
  { int => Number } p = Integer#valueOf(int);
  System.out.println(p.invoke(97));
  

And the contravariant arguments:

  class MyClass {
    static Integer print(Object o) {
      return Integer.valueOf(o.hashCode());
    }
    
    public static void main(String[] args) {
      { String => Number } pp = MyClass#print(Object);
      System.out.println(pp.invoke("hi"));
    }
  }
  

An instance method can be referenced in two ways. Either we reference a method on a given object:

  class Box {
    private int x;
    Box(int x) {
        this.x = x;
    }
    int getX() {
        return x;
    }
  }
  public class InstanceMethod {
    public static void main(String[] args) {
      Box p = new Box(10);
      { => int } getX = p#getX();
      System.out.println(getX.invoke());
    }
  }  
  

Or we reference just a method. Then the function type has an additional argument: the object on which the method is called.

  { Box => int } getX = Box#getX();  // additional argument of type Box
  Box p = new Box(10);
  System.out.println(getX.invoke(p));
  

The method is selected at runtime according to the object supplied as argument. So, in the following example, the toString method from String is called.

  { Object => String } toString = Object#toString();
  System.out.println(toString.invoke("hi"));
  

Generic methods are also supported:

  { String => Set<String> } singleton =
      Collections#<String>singleton(String);
  Set<String> set = singleton.invoke("single");
  

Monday, February 25, 2008

Control Abstraction (version 2008-02-22)

Control Abstraction (version 2008-02-22)

In this post, I will describe new features of version 2008-02-22 of the compiler prototype. It can be downloaded from http://www.javac.info.

1. java.lang.Unreachable was renamed to java.lang.Nothing.

2. Annotation @Shared was added. It may annotate a variable bound in a closure. For example:

  static void doTwice({ => void } block) {
    block.invoke();
    block.invoke();
  }
  public static void main(String[] args) {
    @Shared int x = 10;
    doTwice({ => System.out.println(x++); });
  }
  

We should always annotate bound variables with this annotation because bound variables are very different from ordinary local variables.

3. Closures can use recursion. Now we can use the function variable within a closure that is used to initialize this variable.

  { int => int } sum = { int n => n == 1 ? 1 : n + sum.invoke(n - 1) };
  

4. Unrestricted closures were partially implemented. In an urestricted closure we can use the return, break, and continue statements. Unrestricted closures use ==> instead of =>.

  { int ==> int } neg = { int x ==> -x };
  

5. A method that accepts an unrestricted closure as the last argument can be called using the control invocation syntax:

  public static void simple({ ==> void } block) {
    block.invoke();
    block.invoke();
  }
  public static void main(String[] args) {
    simple() {
      System.out.println("vrr!");
    }
  }
  

The method may have more than one parameter:

  public static void profile(String s, { ==> void } block) {
    System.out.printf(">>> %s: %s%n", s, System.nanoTime());
    block.invoke();
    System.out.printf("<<< %s: %s%n", s, System.nanoTime());
  }
  public static void main(String[] args) {
    @Shared long f = 1;
    profile("factorial") {
      for (int i = 2; i <= 59; i++) {
        f *= i;
      }
    }
  }
  

The closure used as the last argument can have parameters. They are declared before arguments of the method and are separated from them by colon (although the syntax is similar to the enhanced for loop, the colon here has another meaning):

  public static void control(int x, { int ==> void } block) {
    block.invoke(x);
  }
  public static void main(String[] args) {
    // ordinary syntax
    control(1, { int i ==> System.out.println(i); });
    // control invocation syntax
    control(int i : 2) {
      System.out.println(i);
    }
  }
  

If the closure has more parameters, they are separated by comma:

  public static void controlTwo(int x, { int, int ==> void } block) {
    block.invoke(x, x + 1);
    block.invoke(x + 2, x);
  }
  public static void main(String[] args) {
    // closure parameters are separated by comma
    controlTwo(int i, int j : 2) {
      System.out.println(i * j);
    }
  }
  

This enables us to define new "control statements" without modifying the language. For example, we can add "statement" with that closes a given closeable at the end (the code is derived from the prototype sources):

  public static <T extends Closeable> void with(T t, { T ==> void } block) {
    try {
      block.invoke(t);
    } finally {
      try {
        t.close();
      } catch (IOException e) {
        // ignore exception
      }
    }
  }
  public static void main(String[] args) {
    // class MyCloseable implements Closeable
    with (MyCloseable in : new MyCloseable()) {
      //...
    }
  }
  

Why Java cannot remain simple? Do we need new control statements?
Many people like simplicity (I am one of them). But Java must evolve if we do not want it to become outdated. In addition, the hardware is changing and these changes will probably change programming languages used in software development. For information how the hardware is changing, I recommend the article The Free Lunch Is Over: A Fundamental Turn Toward Concurrency in Software. If you are curious how future programming languages may look like, have a look at x10 being developed at IBM. I also recommend the post Is Java dying?

Monday, January 7, 2008

Usage

Usage

In this post, I express my opinion on many places. For example, when I say "it is more intuitive...", I mean "in my opinion, it is more intuitive...".

As we already mentioned, closures are transformed to anonymous inner classes at compile time. So, all we can do with closures, can be done with inner classes as well. However, the access to local variables may require a little effort. For example, the code

  int x = 4;
  { => System.out.println(++x); }.invoke();
  

can be rewritten without closures as follows:

  final int[] x = { 4 };
  new javax.lang.function.V() {
    public void invoke() {
      System.out.println(++x[0]);
    }
  }.invoke();
  

Even if closures do not increase the power of language, in many cases they are more concise and intuitive than other means. They are a natural choice when we want to parameterize an algorithm with a function. For example, sorting may be parameterized with a comparison function:

  Integer[] primes = { 19, 23, 2, 11, 17, 31, 5, 13 };
  Arrays.sort(primes, { Integer x, Integer y => y.compareTo(x) });
  

Here, it is more intuitive to use a function argument than the Comparator interface because the purpose of the argument is only to compare two values.

One should also prefer closures for predicates because predicate is a function:

  static <T> void selectAndPrint(Iterable<T> items, { T => boolean } cond) {
    for (T item: items) {
      if (cond.invoke(item)) {
        System.out.println(item);
      }
    }
  }
  
  public static void main(String[] args) {
    List<String> cities = Arrays.asList(
      "Prague", "San Francisco", "Moscow", "New York", "Paris");
    int max = ...;
    // will print cities that are not longer than max
    selectAndPrint(cities, { String s => s.length() <= max });
    char c = ...;
    // will print cities that contain character c
    selectAndPrint(cities, { String s => s.indexOf(c) >= 0 });
  }
  

Function types can also be used to describe the input of algorithm. For example, a method that returns the size of area under the function curve should have a function argument:

  static double determineFiniteIntegral(
    double from, double to, { double => double } func) {
    double area;
    //...
    return area;
  }
  

Another usage is in a method that takes a block of code as argument. For example, the execute method takes a block that should be performed in a separate thread:

  ExecutorService pool = Executors.newFixedThreadPool(5);
  pool.execute({ => System.out.println("thinking..."); });
  

Again, it is more intuitive and logical to pass a block of code than an object that implements Runnable.

Closures enable us to write methods that behave in a similar way as the foreach loop:

  static void forEach(int[] nums, { int => void } block) {
    for (int n: nums) {
      block.invoke(n);
    }
  }
  
  public static void main(String[] args) {
    int[] p = { 5, 1, 3, 4, 2 };
    int sum = 0;
    forEach(p, { int n => sum += n; }); // will sum up the numbers in array
    int min = Integer.MAX_VALUE;
    forEach(p, { int n => if (n < min) min = n; }); // will find the minimum
  }
  

For example, we can implement a method that performs an operation on each map entry:

  static <K, V> void forEachEntry(Map<K, V> map, { K, V => void } block) {
    for (Map.Entry<K, V> entry: map.entrySet()) {
      block.invoke(entry.getKey(), entry.getValue());
    }
  }
  
  public static void main(String[] args) {
    Map<Integer, String> map = new HashMap<Integer, String>();
    //...
    forEachEntry(map, { 
      Integer key, String value => 
        System.out.println(key + ": " + value); });
  }
  

We can also use closures to implement the visitor design pattern in a simple fashion:

  class Node {
    int value;
    Node left, right;
  }
  
  class Tree {
    Node root;
    //...
    void visitPreOrder({ int => void } block) {
      visitPreOrder(root, block);
    }
    void visitPreOrder(Node p, { int => void } block) {
      if (p != null) {
        block.invoke(p.value);  // first perform the operation on this node
        visitPreOrder(p.left, block);  // then on the left subtree
        visitPreOrder(p.right, block);  // and then on the right subtree
      }
    }
  }
  
  public class TreeOperations {
    public static void main(String[] args) {
      Tree tree = ...;
      List<Integer> nums = new ArrayList<Integer>();
      // will add the numbers to the list
      tree.visitPreOrder({ int v => nums.add(v); });
      //...
    }
  }
  

Completion Transparency

Completion Transparency

Completion transparency enables us to create methods that transparently return the result of a closure which is passed as argument. For example:

  static <T> T withLock(Lock lock, { => T } block) {
    lock.lock();
    try {
      return block.invoke();
    } finally {
      lock.unlock();
    }
  }
  

We can pass to the withLock method a block that returns any value. For example:

  Lock lock = new ReentrantLock();
  Integer i = withLock(lock, { => Integer.valueOf(42) });
  

Due to completion transparency, we can also use a block that does not return anything (i.e. a block of type { => void }):

  withLock(lock, { => System.out.println("mining..."); });
  

And even a block that cannot complete normally, i.e. throws exception (in this case only unchecked exceptions are allowed):

  withLock(lock, { => throw new NullPointerException(); });
  

To allow checked exceptions as well, we can use exceptions transparency:

  static <T, throws E> T withLockEx(Lock lock, { => T throws E} block) 
    throws E {
    lock.lock();
    try {
      return block.invoke();
    } finally {
      lock.unlock();
    }
  }
  
  public static void main(String[] args) {
    try {
      Lock lock = new ReentrantLock();
      withLockEx(lock, { => throw new Exception(); });
    } catch (Exception e) { e.printStackTrace(); }
  }
  

Implementation issue

Let us recall that each closure is converted to an instance of interface. For example, a closure { => System.out.println("buff"); } is converted to an instance of V:

  public interface V {
    void invoke();
  }
  

To achieve completion transparency, the compiler is allowed to use Void instead of void. For example, the code

  withLock(lock, { => System.out.println("miaow"); });
  

will be transformed approximately as follows:

  withLock(lock, new javax.lang.function.O() {
    public Void invoke() {
      System.out.println("miaow");
      return null;
    }
  }
  

In case of closures that do not complete normally, the invoke method returns java.lang.Unreachable which is a special class that is considered a subclass of all classes. This means that an Unreachable may be assigned to any reference variable. For example, the statement

  Integer i = { => throw new NullPointerException(); }.invoke();
  

will be transformed roughly as follows:

  Integer i = new javax.lang.function.O() {
    public Unreachable invoke() { throw new NullPointerException(); }
  }.invoke();