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); });
      //...
    }
  }
  

15 comments:

Václav Slováček said...

I don't believe introducing closures is a good way for Java. Java was appreciated for its simplicity and readability of code. Although closures may seem to be useful at the moment, they can harm Java in long term.

Imagine adding closures to libraries that already exist, that could significantly increase the number of methods in every class and duplicate currently included functionality. I think closures are also confusing for new users and don't help much experienced users as most of the work of anonymous class is done for you by IDE.

I think closures are good only for geeks who like playing with code and don't think making things shorter makes them more readable.

If there were an opportunity to submit ideas for anonymous classes improvements, I would submit "anonymous class by method". Example:

xxx.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
};

replace with:

xxx.addActionListener(new actionPerformed(ActionEvent e) {
}
}

there would have to be probably some sign distinguishing a method from type, but it would make the existing construct shorter while not adding any new functionality to the language itself

the question is whether we can omit public keyword and return type, but I think we can

I believe there are more important things to focus on (media, etc.) than closures that will be welcome only by some developers and hated by others.

Fireblaze said...

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

This is just plain old bad code, since you need a comment just to explain what that line does. See Refactoring by Martin Fowler page 87 or Code Complete by Steve McConnell page 469 - Both say that if you comment in just a repetition of how your code works its plain bad code.

However:

If you can do
sumNumbers = { int n => sum += n; });
forEach(p, sumNumbers);

Then you have good use for clousures since you can explain the code without writing "Coding horrer" - comments.

JimTheDim said...

Closures seem to offer little and intsead introduce us to the wonderful world of cryptic code.

Concise code is not necessarily good code. Code that can be easily understood is alway preferable to concise code.

Give some programmers a means to make their code cryptic and they will use it. Closures will be doing just that. They have no interest in what everyone else who has to look at their code wants, they are only interested in making their code and concise and as cryptic as possible.

Luc Duponcheel said...

Object orientation is sometimes just sitting in the way: if we want to perform a print job, then we need a printer; if we want to do a calculation job, then we need a calculator. Closures let us concentrate on the job. Programming is about elegance, right?

Zdeněk Troníček said...

To jimthedim:

This is not a good argument. Cryptic code can be written already now. For example:

int x = 1, y = 2, z = 3;
z *= y += ++x + x++;

I agree that understandability matters. But the code you write depends on your discipline (and knowledge), not only on means you have.
If you want to write a clear and understandable code, you can do it even with closures. And if you want to write a cryptic code, you do not need closures for it.

JimTheDim said...

I agree that you can already write cryptic code and people do but it is not as easy as, say, in C and C++. Why give people a further ability to write bad code.

I have read some more blogs, etc about Closures and their usages and it just all looks so bad. Easy to miss, hard to understand, easy to make a mistake in.

What these blogs have also thrown up is that people equate the number of lines of code, including blank lines, with how good your code is. Less is better. This is just not true.

What I also would want to know is how a code coverage tool is going to show that you have covered every path in the code.

I have had to review a lot of code for companies. Clever cryptic code has made my life so much harder.

I suspect we will get closures and I also expect I will not use them unless I have to.

Konstantin Triger said...

I would like to propose a small syntax simplification:
Replace <function type>.invoke()
with a simpler <function type>().

I think it will make function types invocations more function-like and hide unnecessary implementation detail.

Zdeněk Troníček said...

To JimTheDim:

Right. Shorter code is not necessary better and I, personally, do not know anybody who claims it is (generaly, not in particular instance). I believe this effort is to remove (or at least minimize) the boilerplate code. Yes, it means that the program will be shorter, but the primary goal is not the length of programs but the boilerplate code.

Zdeněk Troníček said...

Hi Konsta,

we cannot use () instead of invoke(). Look at this:

public class Simple {
static void m() {
System.out.println("hi");
}
public static void main(
String[] args) {
{ => void } m = { =>
System.out.println("hello"); };
m.invoke();
}
}

How would you interpret m() used instead of m.invoke()?

Baldur said...

This would be the same situation with local variables vs class members, or if you have a closure with the same name as a class member.
In such case we can still refer to the class member by using this.m(); :-)

---

I think the main advantage of closures would be situations like
new Thread({ => /* some short task */}).start();
or
Collections.sort(intlist, {int a, int b => a < b});

It doesn't look too cryptic for me...
Shorter code will not always be the better solution, but in such cases I would prefer to give a method a short piece of code than writing a complete class for it.
This could be even more ugly, if someone would try to make it 'short'
new Thread(new Runnable(){public void run() { /* do something */ }}).start();

Anonymous said...

I've been coding for over 25 years, and 10 years of which have been Java. After been a bystander on the closure issue for many months, and remaining objective throughout, I've arrived at my own conclusion: closure as it is currently designed does not provide enough value to me, or to change the JLS for.

"Simplicity is the ultimate sophistication." Java succeeded in becoming a viable alternative to C/C++ because it *simplified* C/C++ and made itself accessible to the masses. Keeping Java simple will ensure its longevity. Closures as it is currently being designed is too difficult. I also doubt if enough people will find it useful, especially when it is neither essential nor critical to writing code that works.

Jo D. said...

I am just horrified by the syntax. The syntax laid out here is clearly foreign to Java. Why not even make it look like a Java method definition, including a return that works only in the scope of the closure, drop the invoke. Make it work like one would expect from Java.

Anonymous said...

Mhmm ... bold arrow does not look very good.

For me more readable and 'Java compliant' is return, so instead of

{ int x, int y => x+y; }

I would like to see smthing like this:

{ (int x, int y) return x+y; }

Toko Jual Obat Kuat Alat Bantu Sex 087733776655 said...

Klik Aja Di Bawah Ini
Pemesanan: 087733776655
http://obatkuat-57.com/
Jual Obat Pembesar Penis Vigrx Plus
Alat Bantu Sex Pria Dan Wanita
Rajanya Obat Kuat Sex
Obat Perangsang Wanita, Obat Gairah Wanita
Obat Pembesar Payudara Monyok, Payudara Kencang
Alat Pembesar Payudara Montok
Alat Pembesar Penis
Alat Sex Pria Boneka Moderen
Obat Pengental Sperma
Minyak Pembesar Penis, Obat Pemanjang Penis
Obat Hernia Paling Ampuh
Obat Pelangsing Badan, Melangsingkan Tubuh
Obat Perapet Vagina
Obat Peninggi Badan, Meninggikan Bada
Obat Pembesar Pantat, Pembesar Bokong
Obat Pemerah Bibir, Pemerah Puting
Obat Pemutih Wajah Alami Tensung Cream
Obat Penggemuk Badan
Obat Penghilang Tatto Permanen Herbal Alami
Kondom Antik Pria
Rajanya Obat Kuat Pria
Alat Bantu Sex Wanita Antik
Alat Bantu Sex Pria
Obat Kuat Herbal
Vimax Obat Pembesar Alat Vital
Cara Memutihkan Selangkangan dan Ketiak


Obat Pelangsing Badan Fatloss Jimpness Beauty
Selaput Dara Perawan Buatan


Radley Co Tad said...

Very much useful article. Kindly keep blogging

Java Training in Chennai

Java Online Training India