Friday, December 28, 2007

Function Types

Function Types

Function types are used when we want to refer to closures. We can declare a variable of function type and assign to it a reference to a closure. A function type is written as follows: { formal parameters => return type }. Formal parameters are optional. The return type can be any type or void. For example, { int, String => void } means a function with two arguments (int and String) and return type void. Any function with a compatible list of argument types and compatible return type can be assigned to a variable of function type.

  public class DeepThought {
  
    // { => int } means a function with no arguments and return type int
    static { => int } answer = { => 42 };
 
    public static void main(String[] args) {
      int i = answer.invoke();
      System.out.println(i);
    }
 
  }
  

A function with one int argument and return type String:

  { int => String } toBinary = { int x => Integer.toBinaryString(x) };
  String binary11 = toBinary.invoke(11);  // will return 1011
  

A function with no arguments and return type void:

  { => void } sayHello = { => System.out.println("Hello"); };
  sayHello.invoke();  // will print "Hello"
  

Function types can be used as types of arguments:

  static void doTwice({ => void } block) {
    block.invoke();
    block.invoke();
  }
  
  public static void main(String[] args) {
    doTwice({ => System.out.println("deja vu"); });
  }
  

They can also serve as a return type:

  static { => boolean } makeCond() {
    return { => Math.random() < 0.8 };
  }
  
  public static void main(String[] args) {
    { => boolean } cond = makeCond();
    while (cond.invoke()) {
      System.out.println("trying...");
    }
  }
  

Exercises

  1. Write a method that invokes an action on each value of array of ints. The action is passed in a function variable.
  2. Write a method that returns a closure which checks if a value is from a given interval. Bounds of the interval are arguments of the method.
  3. Write a method that selects values from a list in accordance with a predicate passed in a function variable.

Solutions

  static void perform(int[] values, { int => void } action) {
    for (int n: values) {
      action.invoke(n);
    }
  }
  
  public static void main(String[] args) {
    int[] v = { 2, 3, 5, 7, 11 };
    perform(v, { int x => System.out.println(x); });
  }
  
  static { int => boolean } makeInterval(int a, int b) {
    return { int x => a <= x && x <= b };
  }
  
  public static void main(String[] args) {
    { int => boolean } interval = makeInterval(10, 20);
    System.out.println(interval.invoke(15));
  }
  
  static <T> List<T> select(List<T> values, { T => boolean } cond) {
    List<T> selected = new ArrayList<T>();
    for (T t: values) {
      if (cond.invoke(t)) { selected.add(t); }
    }
    return selected;
  }
  
  public static void main(String[] args) {
    List<String> cities =
      Arrays.asList("London", "New York", "Prague", "San Francisco");
    List<String> shortCities = 
      select(cities, { String s => s.length() <= 6 });
    System.out.println(shortCities);
  }
  

12 comments:

Anonymous said...

http://blog.dabarobjects.com/?p=26

Krishna Bhargava Vangapandu said...

So essentially with function types you could simulate the behavior of a Function Pointer or Delegates(C#/VB).

/** Java Program to demonstrate delegates using closures! **/
class DelegateDemo
{
/** You must always specify return types! **/
static { => void } method1 = { => System.out.println("This is method 1"); };
static { => void } method2 = { => System.out.println("This is method 2"); };

/** A method which takes a delegate of type void xyz(); **/
static void invoker({=> void} anyMethod)
{
anyMethod.invoke();
}

public static void main(final String[] args) {
invoker(method1);
System.out.println("Now passing method2!!");
invoker(method2);
}
}

Hope I am right!

Bhargav
krishnabhargav.blogspot.com

Zdeněk Troníček said...

I am afraid you are not because there is no way how to assign a method reference to a variable of function type.

Christian Ullenboom said...

Function pointers are valid:

public class FunctionPointerWithClosures
{
static void invoker( { => void } block )
{
block.invoke();
}

public static void main( String[] args )
{
{ => void } method1 = { => System.out.println("Hello tutego"); };
{ => void } method2 = { => System.out.println("Hallo tutego"); };

invoker( Math.random() > 0.5 ? method1 : method2 );
}
}

Christian Ullenboom | http://www.tutego.com/

Konstantin Triger said...

...there is no way how to assign a method reference to a variable of function type.

That's right, but we are close and compiler can greatly help.
Suppose you have:

class Foo {
int test(short){}
}

Foo foo;

Now
{short => int} x = foo.test;

can be converted to:
{short => int} x = {short s => foo.test(s)};

and

{Foo,short => int} x = Foo.test;

can be converted to:
{Foo,short => int} x = {Foo f, short s => f.test(s)};

What do you think?

Zdeněk Troníček said...

There is a new compiler prototype (published today, 2008-03-17). It contains a support for function pointers. For example:

{ int => Integer } box = Integer#valueOf(int);
Integer i = box.invoke(3);

So, you were right. We were not very far :o).

Konstantin Triger said...

Thanks for an update!

Some functionality questions:
1. Does it handle instance methods? (Both cases: instance is specified and instance is not specified).
2. Is there any any restrictions regarding access modifiers? (There should not be, yet is it possible to call a private method?)
3. Suppose you support instance methods, do you correctly distinguish between myVirtualMethod() and super.myVirtualMethod()?

Kosta
Java Query library,
http://jaque.googlecode.com

Zdeněk Troníček said...

Good questions. Yes, there are restrictions caused by access modifiers. So, for example, you cannot call a private method. The next two questions I tried to answer in my new post "Method References".

Anonymous said...

What the interests of that ?
I don't understand.
Except make the code more ugly and obscur.
Why not do play with interface, and class properly ?
Something like :

--- File Invokable.java ---
public interface Invokable
{
public void invoke();
}

---- File Method1.java ----
public class Method1 implements Invokable
{
public void invoke()
{
System.out.println("method1");
}
}

---- File Method2.java ----
public class Method2 implements Invokable
{
public void invoke()
{
System.out.println("method2");
}
}

--- File Invoker.java ---
public class Invoker
{
public static void invoke(Invokable invokable)
{
invokable.invoke();
}
}

--- File Test.java ---
public class Test
{
public static void main(String[] args)
{
Method1 method1 = new Method1();
Method2 method2 = new Method2();

Invoker.invoke( Math.random() > 0.5 ? method1 : method2
}
}

---------------------------------

Like a good Java developer do.

Why build new syntax for a solution that already exists ?

I know my exemple is not the best, but it shows what is behind my head.

Radley Co Tad said...

Very much useful article. Kindly keep blogging

Java Training in Chennai

Java Online Training India

daizymathew said...

Thanks for sharing this useful information.

obata datang bulan said...

Jual Obat Aborsi Asli | Obat Cytotec Asli | 082241083319
jual obat aborsi pills cytotec asli manjur untuk menggugurkan kandungan usia 1 - 6 bulan gugur tuntas.CYTOTEC OBAT ASLI sangat efektif mengatasi TELAT DATANG BULANdan menjadikan anda gagal hamil , CYTOTEC adalah OBAT ABORSI 3 JAM BERHASIL GUGUR TUNTAS dengan kwalitas terbaik produk asli pfizer nomor 1 di dunia medis

JUAL OBAT ABORSI DI BREBES
JUAL OBAT ABORSI DI CILACAP
JUAL OBAT ABORSI DI DEMAK
JUAL OBAT ABORSI DI GROBOGAN
JUAL OBAT ABORSI DI PRWODADI
JUAL OBAT ABORSI DI JEPARA