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

10 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.

daizymathew said...

Thanks for sharing this useful information.