Protótipo de Closures em Java está "feature-complete"

Do blog de Neal Gafter:

I’m pleased to announce that the Java Closures prototype now supports all of the features of its specification!

The complete source code, released under GPLv2, is in the project’s openjdk repository. A binary build, suitable for use with an existing JDK6, is at http://www.javac.info/closures.tar.gz. Other related documents are on the website http://www.javac.info/.


Mais informações em: http://gafter.blogspot.com/2008/08/java-closures-prototype-feature.html
E para quem quiser conhecer um pouco mais da proposta de closures: http://www.parleys.com/display/PARLEYS/Home#talk=2097237;;slide=1

Baixei o protótipo e brinquei um pouquinho…

[code]
public class HelloClosures1 {

public static void main(String args[]) {
	{ int, int => int } soma = { int a, int b => a + b };
	System.out.println(soma.invoke(1,2));
}

}
[/code]Saída: 3

[code]
import java.util.*;

interface ListClosure extends List {
public ListClosure extract({ E => boolean } block);
}

class ArrayListClosure extends ArrayList implements ListClosure {

public ListClosure<E> extract({ E => boolean } block) {
	ListClosure<E> lista = new ArrayListClosure<E>();
	for (E elem : this) {
		if (block.invoke(elem)) {
			lista.add(elem);
		}
	}
	return lista;
}

}

public class HelloClosure2 {

public static void main(String args[]) {
	Integer[] numeros = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	ListClosure<Integer> lista = new ArrayListClosure<Integer>();
	lista.addAll(Arrays.asList(numeros));
	
	ListClosure<Integer> filtrada = lista.extract({ Integer a => a % 2 == 0 });
	System.out.println(filtrada);
}

}
[/code]Saída: [0, 2, 4, 6, 8, 10]

Achei muito legal porque as closures ficaram tipadas…

Se bem que em flex acaba ficando mais simples…

var soma:Function = function (a:int, b:int):int {
return a + b;
};
soma(1, 2);

Mas gostei… mesmo assim =D

VELO

PO!

Tentei rodar o primeiro exemplo e tomei um

Exception in thread "main" java.lang.NoClassDefFoundError: java/lang/RestrictedFunction at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:638) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:143) at java.net.URLClassLoader.defineClass(URLClassLoader.java:281) at java.net.URLClassLoader.access$000(URLClassLoader.java:74) at java.net.URLClassLoader$1.run(URLClassLoader.java:216) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:209) at java.lang.ClassLoader.loadClass(ClassLoader.java:324) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294) at java.lang.ClassLoader.loadClass(ClassLoader.java:269) at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:337) Caused by: java.lang.ClassNotFoundException: java.lang.RestrictedFunction at java.net.URLClassLoader$1.run(URLClassLoader.java:221) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:209) at java.lang.ClassLoader.loadClass(ClassLoader.java:324) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294) at java.lang.ClassLoader.loadClass(ClassLoader.java:269) at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:337) ... 12 more Error: Could not find the main class. Error: A JNI error has occurred, please check your installation and try again

Instalei o jdk7 no ubuntu via apt-get, alguem passou por isso ? :confused:

Tiago, use o javac e o java que vêm no arquivo disponibilizado pelo Neal Gafter.

[quote=peczenyj]PO!

Tentei rodar o primeiro exemplo e tomei um

Exception in thread "main" java.lang.NoClassDefFoundError: java/lang/RestrictedFunction

Instalei o jdk7 no ubuntu via apt-get, alguem passou por isso ? :/[/quote]

Problema de classpath Tiago. Ele pegou o rt.jar do seu java antigo ja instalado, tinha de pegar do java “turbinado”. usa o java que vem com ele, ou altera o bootclasspath do seu atual para passaer pelos jars do prototipo.

Putz, rateei no mais obvio… consegui rodar o primeiro exemplo sim, muito legal!!!

Olha q codigo divertido do primeiro exemplo!

[code]$ javap A
Compiled from "A.java"
public class A extends java.lang.Object{
public static final A$2 +INSTANCE0;
public A();
public static void main(java.lang.String[]);
static {};
}

$ javap A$1
Compiled from "A.java"
final class A$1 extends java.lang.Object{
javax.lang.function.III 1$soma;
A$1();
}

$ javap A$2
Compiled from "A.java"
final class A$2 extends java.lang.Object implements javax.lang.function.III{
A$2();
int +invoke(int, int);
public final int invoke(int, int);
}[/code]

:shock:

A sintaxe para invocar é meio ruim, tem um “.invoke” supérfluo nisso.

Fora que a performance quando o compilador introduz boxing por baixo dos panos deve ser terrível.

Declarar os tipos dos parâmetros de entrada duas vezes ( uma no cabeçalho da closure e outra no seu corpo ) é chato demais…

Advanced Topics In Programming Languages: Closures For Java [size=18] ; )[/size]

[youtube]http://www.youtube.com/watch?v=0zVizaCOhME[/youtube]

Acho que será mais comum fazer algo desse tipo:

public static int doIt({ int, int =&gt; int } closure){ return closure.invoke(3,2); }

Ou isso:

Um pouco menos chato, concorda ?

Bem melhor ( só não entendi a necessidade de parênteses ao redor do bloco de código na segunda forma - acho que o chato aqui sou eu mesmo :stuck_out_tongue: ).

Eu tenho uma dúvida ( leia os comentários do código abaixo ):

class TesteClosure { public static void main(String args[]) { int five = 5; // Declarando a closure no estilo do peczenyj ( sem os parênteses ) int x = fiveTimes { int a =&gt; a * five }; // Isto aqui imprime 15 System.out.println(fiveTimes.invoke(3)); five = 10; // E isto aqui imprime quanto? 15 ou 30? System.out.println(fiveTimes.invoke(3)); } }
Se seguir o conceito de closures ( que mantém sempre o contexto original de sua declaração ), o segundo System.out.println deveria imprimir 15.

Eu não estava declarando uma closure na segunda forma e sim invocando-a através do método estático doIt declarado no primeiro, mas tenho que praticar mais.

Ah sim, entendi.
Confundi porque ficou muito semelhante com a forma que o David escreveu, mas sem a dupla declaração:

Daí achei que doIt fosse o nome da closure.

Acho que será mais comum fazer algo desse tipo:

public static int doIt({ int, int =&gt; int } closure){ return closure.invoke(3,2); }

Ou isso:

Um pouco menos chato, concorda ?[/quote]

Não se espantem mas já dá pra fazer isso em Delphi há anos!

Realmente podemos ter um comportamento semelhante a closures em Delphi, conforme post abaixo:
http://barrkel.blogspot.com/2006/08/delphi-closures-anonymous-delegates.html
Mas será que a suposta closure declarada mantém seu contexto original? Caso negativo, não são closures, e sim, ponteiros para blocos de código. Infelizmente tô sem o Delphi aqui pra fazer o teste.

Pela madrugada, java está se tornando uma linguagem extra-terrestre, daqui a pouco so os ETs vão entender isso.

heheeheheh…

[quote]

[code]
import java.util.*;

interface ListClosure extends List {
public ListClosure extract({ E => boolean } block);
}

class ArrayListClosure extends ArrayList implements ListClosure {

public ListClosure<E> extract({ E => boolean } block) {
	ListClosure<E> lista = new ArrayListClosure<E>();
	for (E elem : this) {
		if (block.invoke(elem)) {
			lista.add(elem);
		}
	}
	return lista;
}

}

public class HelloClosure2 {

public static void main(String args[]) {
	Integer[] numeros = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	ListClosure<Integer> lista = new ArrayListClosure<Integer>();
	lista.addAll(Arrays.asList(numeros));
	
	ListClosure<Integer> filtrada = lista.extract({ Integer a => a % 2 == 0 });
	System.out.println(filtrada);
}

}
[/code]Saída: [0, 2, 4, 6, 8, 10][/quote]

Mesmo programa escrito em Scheme:

(define extrai
  (filter (lambda (numero) (even? numero))
    '(0 1 2 3 4 5 6 7 8 9 10)))

Saida: (0 2 4 6 8 10)

:shock:

E em Python, alguem ai?

Imaginem poder enviar blocos de código à uma List ou Comparable, ficando cada vez mais parecido com Ruby.

To curioso pra ver como serão os Extension Methods, ficaria show de bola:

[code]class EnhancedInteger {
static boolean greaterThanAll(Integer self, Object[] others) {
greaterThanAll(self, others)
}
static boolean greaterThanAll(Integer self, others) {
others.every{ self > it }
}
}

use(EnhancedInteger) {
assert 4.greaterThanAll(1, 2, 3)
assert !5.greaterThanAll(2, 4, 6)
assert 5.greaterThanAll(-4…4)
assert 5.greaterThanAll([])
assert !5.greaterThanAll([4, 5])
}[/code]

Sinto cheiro de migração da galera pra outra sintaxe, mas a JVM é eterna. Concordam?

[quote=cmoscoso][quote]

[code]
import java.util.*;

interface ListClosure extends List {
public ListClosure extract({ E => boolean } block);
}

class ArrayListClosure extends ArrayList implements ListClosure {

public ListClosure<E> extract({ E => boolean } block) {
	ListClosure<E> lista = new ArrayListClosure<E>();
	for (E elem : this) {
		if (block.invoke(elem)) {
			lista.add(elem);
		}
	}
	return lista;
}

}

public class HelloClosure2 {

public static void main(String args[]) {
	Integer[] numeros = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	ListClosure<Integer> lista = new ArrayListClosure<Integer>();
	lista.addAll(Arrays.asList(numeros));
	
	ListClosure<Integer> filtrada = lista.extract({ Integer a => a % 2 == 0 });
	System.out.println(filtrada);
}

}
[/code]Saída: [0, 2, 4, 6, 8, 10][/quote]

Mesmo programa escrito em Scheme:

(define extrai
  (filter (lambda (numero) (even? numero))
    '(0 1 2 3 4 5 6 7 8 9 10)))

Saida: (0 2 4 6 8 10)

:shock:

E em Python, alguem ai?[/quote]

Em Python, não sei. Mas em Ruby, fica assim:

lista = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
puts lista.select {|a| a % 2 == 0}

Apesar que eu acho que você foi injusto com Java, pois boa parte do seu código é para adicionar um método em ArrayList. Na prática, quando Closure for real, novos métodos serão (ou deveriam ser) adicionados nas coleções, e ninguém fará isso à mão.

Portanto, para comparação, vou considerar no código Java apenas a classe com método estático main.
Fica assim:

Java (com closure) -> 9 linhas
Scheme -> 3 linhas
Ruby -> 2 linhas