Disponível primeiro protótipo de Closures

21 respostas
T

O primeiro protótipo de Closures (recurso da linguagem que talvez seja incluído no Java 6 ou 7) está disponível.

Veja o post do sr. Neal Gafter em: http://gafter.blogspot.com/2007/10/java-closures-first-prototype.html
Um exemplo de programa com Closures:

import java.security.*;

interface StringIntDouble {
    double invoke (String s, int x);
}

class TesteClosures {

    /** Exemplo de closures - "closure literal"  */
    public void test1() {
        // Sintaxe de closures
        {String,String=>String} fn =  
            {String x, String y => x + "," + y};
        System.out.println (fn.invoke ("ab", "c"));
        // (Deve imprimir: "ab,c"
    }
    /** Exemplo de várias exceções tratadas com um único catch */
    public void test2() {
        MessageDigest md;
        try {
            md = MessageDigest.getInstance ("MD2", "SunJCE");
        } catch (NoSuchAlgorithmException | NoSuchProviderException ex) {
            ex.printStackTrace();
        } finally {
            System.out.println ("test2");
        }
    }
    /** Exemplo de "closure conversion" */
    public void test3() {
        StringIntDouble obj2 = {String s, int x => (double) 42.0};
        StringIntDouble[] obj3 = {
           {String s, int x => (double) 1.0},
           {String s, int x => (double) 2.0}
        };
        // Note que não se pode fazer isto:
        // porque gera o erro "generic array creation".
        // {String,int=>double} [] obj4 = {
        //   {String s, int x => (double) 1.0},
        //   {String s, int x => (double) 2.0}
        // };

        System.out.println (obj2.invoke ("abc", 4));
        System.out.println (obj3[0].invoke ("abc", 6));
    }


    public static void main(String[] args) {
        TesteClosures tc = new TesteClosures();
        tc.test1();
        tc.test2();
        tc.test3();
    }
}

21 Respostas

T

Outro exemplo (em que criamos um Comparator que aceita qualquer Closure):

import java.util.*;

class ClosureComparator<T> implements Comparator<T> {
    private {T, T => int} closure;
    public ClosureComparator({T, T => int} closure) {
        this.closure = closure;
    }
    public int compare (T obj1, T obj2) {
        return closure.invoke (obj1, obj2);
    }
}

class Cliente {
    public String nome;
    public double divida;
    public Cliente (String nome, double divida) { this.nome = nome; this.divida = divida; }
    public String toString() { return "(" + nome + "," + divida + ")"; }
}

class TesteClosures2 {
    public static void main(String[] args) {
        List<Cliente> clientes = new ArrayList<Cliente>();
        clientes.add (new Cliente ("José Aparecido", 100.0));
        clientes.add (new Cliente ("Luís Inácio", 200.0));
        Collections.sort (clientes, new ClosureComparator<Cliente>({Cliente x, Cliente y => 

x.nome.compareTo (y.nome)}));
        System.out.println (clientes);
    }
}
T

Muito bom!!! Gostei!!! Sómente não gosto muito do incremento de sintaxe…

ddduran

Na boa, desculpe a ignorancia, mas que beneficios isso vai trazer?
que outra linguagem tem esse recurso?

não vi nada ai que não podesse fazer de maneira bem mais legivel

no java 6 provavelmente não será mais incluido :smiley:

T

no java 7, no 6 não

T

Escrevi Java 6 ou 7, mas na verdade seria 7 (Dolphin) ou 8 (não sei o nome código).

De qualquer maneira, os benefícios de closures são um pouco sutis, tanto é que muita gente está contra sua introdução na linguagem.

Quem nunca programou em outras linguagens com closures tem uma das seguintes opiniões:

  • Não entendi e não gostei
  • Até entendi, mas nada que uma anonymous class não resolva

Quem já programou com linguagens com closures tem uma das seguintes opiniões:

  • Em Java ficou complicado demais
  • Parece uma cópia mal-ajambrada do mesmo recurso que existe no Groovy

Linguagens com closures: Smalltalk, Groovy, Ruby, Python, Scala, C# (Visual Studio 2008), etc.

peczenyj

O que eu acho estranho é esta sintaxe:

{int, int => int} closure;

Ok, não tem outra forma de fazer em Java que não seja esta mas em que ponto este recurso é diferente de uma classe interna anônima?

Parece um syntax sugar.

ddduran

eu estou nesse grupo ai :stuck_out_tongue: hehehe

mas eu até entendi o codigo (com base nos prints), só não consegui ter a visão no que isso vai agregar.

T

Bom, não mostrei ainda os outros recursos de closures porque o protótipo ainda não os suporta.
Uma coisa que é muito legal é a implementação do comando “using” do C#, mas sem precisar de chumbar isso na linguagem.
Para quem não sabe o que é isso, o “using” serve para fechar (no C#), na marra, qualquer coisa que você definir como “fechável” - um Connection, um InputStream etc, sem que você precise usar um monte de “try/catch/finally”. Exemplo:

using (InputStream inps = new FileInputStream("teste.bin")) {
     byte[] buffer = new byte[1024];
     inps.read(buffer);
}

seria o equivalente a:

InputStream inps = null;
try {
    inps = new FileInputStream ("teste.bin");
    byte[] buffer = new byte[1024];
    inps.read (buffer);
} finally {
    try {if (inps != null) inps.close();} catch (IOException ex) {}
}

o que é uma maravilha para esse tipo de código chato e sujeito a erros.

_fs

Ótimo ;D

Apesar de não ter pensado nas implicações disso, eu realmente preferi a sugestão do eirikma nos comentários.
Ao invés disso,

void cumulate({double,double=>double} reducer, double base)

isso:

void cumulate(double reduce(double currentChoice, double nextCandidateValue), double base)
rodrigoallemand

Acho que pro pessoal do Groovy, do RoR entre outras isso fica mais fácil de entender… mas pro pessoal que não viu, seja por qualquer motivo, fica mais dificil… Eu, por exemplo, nunca vi Groovy ou RoR por falta de tempo e de interesse… Java tá me deixando bastante ocupado ainda!!! hehehehe

T

O eirikma está vendo que nesse caso em particular, um closure é algo parecido com um ponteiro de função, e ele está propondo uma sintaxe semelhante a ponteiros de função que é similar à maior parte das linguagens orientadas a objetos (C++, Object Pascal etc.).

Rodrigo_Carvalho_Aul

[quote=LIPE]void cumulate({double,double=>double} reducer, double base)
isso:

void cumulate(double reduce(double currentChoice, double nextCandidateValue), double base)

Os dois me parecem confusos. Poderia ter a possibilidade fazer como os delegates do C#.

class Test {
    closure double Reduce(double currentChoice, double nextCandidateValue);

   void cumulate(Reduce reduce, double base) {
        ...
   }
}

E pra que invoke?

Pq não simplesmente:

System.out.println (fn("ab", "c"));

[]'s

Rodrigo Auler

T

Por isso é que é um protótipo.
Provavelmente esse “invoke” vai acabar caindo fora, já que não é ortogonal (comparando com a sintaxe clássica de chamada de funções através de ponteiros, como é o caso do C++ ou do Object Pascal.). É isto que você estava mencionando?

class ClosureComparator<T> implements Comparator<T> {  
     private {T, T => int} closure;  
     public ClosureComparator({T, T => int} closure) {  
         this.closure = closure;  
     }  
     public int compare (T obj1, T obj2) {  
         return closure (obj1, obj2);  
     }  
 }
Rodrigo_Carvalho_Aul

Mais ou menos, do jeito que vc mostrou tem que ficar repetindo {T, T => int} cada vez que tiver que declarar a closure. Seria bom ter uma maneira de evitar essa repetição.

[]'s

Rodrigo Auler

T

Uma coisa que seria bom é ter algo como um “typedef” do C++; isso ajudaria bastante em Generics também.
Foi sugerido isso para a Sun e está na lista de bugs.sun.com.

diego2005

ddduran:
thingol:

Quem nunca programou em outras linguagens com closures tem uma das seguintes opiniões:

  • Não entendi e não gostei

eu estou nesse grupo ai :stuck_out_tongue: hehehe

mas eu até entendi o codigo (com base nos prints), só não consegui ter a visão no que isso vai agregar.

Eu também, rsrrrsrsr…

jack_ganzha

É difícil fazer Java aceitar closures como Ruby ou Groovy por causa da tipagem estática. Eu não gostei muito da sintaxe e também acho que o invoke deve ser removido já que não faz sentido. Um problema nessas inserções na linguagem é que as APIs mais usadas de Java estão congeladas e não aproveitam os beneficios. A de collections, por exemplo, onde closures seriam bem interessantes, não vai sofrer alteração porque adicionar um método a java.util.List quebra compatibilidade de maneira muito forte.

valeuz…

louds

[quote=LIPE]Ótimo ;D

Apesar de não ter pensado nas implicações disso, eu realmente preferi a sugestão do eirikma nos comentários.
Ao invés disso,

void cumulate({double,double=>double} reducer, double base)

isso:

void cumulate(double reduce(double currentChoice, double nextCandidateValue), double base)

Por alguns motivos:

:arrow: Gramática ambigua, a notação no protótipo e no corpo de uma função seria diferente. “nome” “(” parametros “)” é a notação para aplicação, IOW chamada de método.

:arrow: A outra opção é mais sussinta, não existe necessidade do nome dos parâmetros.

:arrow: Assinaturas de tipos em Java sempre foram constituidas de forma a suportar comparação lexicográfica. Logo “double reduce(double a, double b)” seria um tipo diferente de “double usaDoze(double naCara, double funeralJaEra)”. Enquanto isso “{double,double => double}” é uma só.

:arrow: O Neal curte linguagens funcionais, o grande lance dele seria usar “Double -> Double -> Double” e suportar currying arbitrário. Porém ele sabe ele dificilmente conseguiria que uma fração ínfima dos usuários de Java aprende-se isso.

ddduran, uma enorme quantidade de linguagens suportam alguma forma de closures. Entre as mais conhecidas: JavaScript, Ruby, C# (via anonymous delegates no 2.0), Clipper, Groovy, Smalltalk, Haskell, Scala, Nemerle e a lista vai longe.

peczenyj, não é apenas sugar sobre classes anônimas, é uma melhoria enorme. Classes anônimas só capturam variaveis locais final, o contexto delas interfere no da classe (tenta chamar “toString” dentro delas"), simular flow control com elas é um parto e a lista só aumenta.

Rodrigo, delegates (mesmo com captura de contexto) são uma abstração inferior a closures. E mesmo que fosse melhor, a Sun tem a obrigação política de jamais incluir isso no Java depois do enorme bate-boca que isso gerou na época do J++. A MS adicionou suporte a delegates na linguagem e isso criou uma celeuma como nunca se viu antes. Quanto a ter que ficar repetindo a assinatura, bom, se não aprenderam isso antes com generics, vc acha que vai ser agora?

Mauricio_Linhares

Assim, bom que eles estejam colocando isso na linguagem, melhor ainda que a sintaxe tá bem parecida com a sintaxe de Scala, mas é aquela coisa, quem vai usar mesmo isso já tá programando em Groovy e/ou Scala, não vai esperar o Java 7 ou 9 pra ver isso funcionar não.

Thiagosc

thingol:
De qualquer maneira, os benefícios de closures são um pouco sutis, tanto é que muita gente está contra sua introdução na linguagem.

Quem nunca programou em outras linguagens com closures tem uma das seguintes opiniões:

  • Não entendi e não gostei
  • Até entendi, mas nada que uma anonymous class não resolva

Quem já programou com linguagens com closures tem uma das seguintes opiniões:

  • Em Java ficou complicado demais
  • Parece uma cópia mal-ajambrada do mesmo recurso que existe no Groovy

Olha, eu sei um pouco de Lisp e posso te dizer que se Closures fosse 1/100 da quantidade de hype que existe em volta disso estaríamos salvos. Fato é que Closures nada mais são que um poor-man’s-object. É um objeto simples que salva os argumentos usados e possui um único método chamado “invoke”.

Isso é uma adição bem-vinda, mas não revolucionará a vida de ninguém, apenas facilitará as coisas assim como o “novo for loop” fez a gente economizar código para iterar ou generics poupou-nos o trabalho de fazer casts e ajudou a prevenir erros com tipos.

louds

Thiagosc:

Olha, eu sei um pouco de Lisp e posso te dizer que se Closures fosse 1/100 da quantidade de hype que existe em volta disso estaríamos salvos. Fato é que Closures nada mais são que um poor-man’s-object. É um objeto simples que salva os argumentos usados e possui um único método chamado “invoke”.

Isso é uma adição bem-vinda, mas não revolucionará a vida de ninguém, apenas facilitará as coisas assim como o “novo for loop” fez a gente economizar código para iterar ou generics poupou-nos o trabalho de fazer casts e ajudou a prevenir erros com tipos.

Concordo em parte com você, mas a maior facilidade é por conta da sintaxe muito mais enxuta em relação a inner classes.

Criado 29 de outubro de 2007
Ultima resposta 1 de nov. de 2007
Respostas 21
Participantes 12