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
- Write a method that invokes an action on each value of array of ints. The action is passed in a function variable.
- 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.
- 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:
http://blog.dabarobjects.com/?p=26
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
I am afraid you are not because there is no way how to assign a method reference to a variable of function type.
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/
...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?
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).
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
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".
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.
Thanks for sharing this useful information.
Post a Comment