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

95 respostas
D

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...
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));
	}
	
}
Saída: 3
import java.util.*;

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

class ArrayListClosure<E> extends ArrayList<E> implements ListClosure<E> {
	
	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);
	}
	
}
Saída: [0, 2, 4, 6, 8, 10]

95 Respostas

V

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

P

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:

D

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

P

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 ? :/

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.

P

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

Olha q codigo divertido do primeiro exemplo!

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

:shock:

L

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.

T

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

M

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

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

P

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 ?

T

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.

P

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.

T

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.

R

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 ?

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

T

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.

O

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

heheeheheh…

C
import java.util.*;

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

class ArrayListClosure<E> extends ArrayList<E> implements ListClosure<E> {
	
	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);
	}
	
}
Saída: [0, 2, 4, 6, 8, 10]

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?

P

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:

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])
}
P

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

L
cmoscoso:
import java.util.*;

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

class ArrayListClosure<E> extends ArrayList<E> implements ListClosure<E> {
	
	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);
	}
	
}
Saída: [0, 2, 4, 6, 8, 10]

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?

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

L

Mais um, em Javascript (copie todo o código, jogue num html e veja no browser):

<script type="text/javascript">
	var lista = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

	Array.prototype.select = function(selectorFunction) {
		var result = [];

		for (var i = 0; i < this.length; i++) {
			if (typeof selectorFunction == "function" && selectorFunction(this[i])) {
				result.push(this[i]);
			}
		}
		return result;
	}

	document.write(lista.select(function(e) {return e % 2 == 0}));
</script>

Porém, Javascript não tem suporte nativo para filtragem em Array, mas tem closure! Por isso, tive que adicionar um método select no Array.
Fica assim:

Java com closure -> 24 linhas
Javascript -> 11 linhas
Java com closure (apelando pra não considerar customização de ArrayList) -> 9 linhas
Scheme -> 3 linhas
Ruby -> 2 linhas

M

"

P

Acho melhor ter uma linguagem que tem várias maneiras de fazer coisas semelhantes de modo elegante do que ter uma linguagem que tenta fazer isso de modo deselegante. Ficou feinho e burocrático utilizar closures em java, e espero que o uso disso não seja abusado no futuro.

T+

M

Poderíamos migrar todos pra Scala e sermos felizes para sempre :slight_smile:

T

Toda vida que um recurso novo é adicionado a linguagem, a história se repete. Na época de Generics, muita gente torceu o nariz e no final todos viram que é bom.
Às vezes acho a comunidade mais exigente que o necessário, minha opinião. Vejo linguagens como C# agregarem muitos recursos durante sua evolução, e em Java é a maior ladainha pra colocar algo novo.

R

Porque em vez de ficar fazendo remendos eles não criam algo novo do zero? :?

M

tnaires:
Toda vida que um recurso novo é adicionado a linguagem, a história se repete. Na época de Generics, muita gente torceu o nariz e no final todos viram que é bom.
Às vezes acho a comunidade mais exigente que o necessário, minha opinião. Vejo linguagens como C# agregarem muitos recursos durante sua evolução, e em Java é a maior ladainha pra colocar algo novo.

Todos quem cara-pálida?

A implementação de generics em java é sebosa e não existe informação nenhuma sobre os genéricos em tempo de execução, obrigando a construção de gambiarras (como passar o Class<T> quando você já passou T em algum lugar, não haver T[]). Uma feature que adiciona um absurdo de complexidade acidental, sem adicionar quase nada em funcionalidades. E a falta de type-inference faz o código generico ser desnecessariamente feio.

T

E espero que na nova versão eles não façam mais a gente ficar passando Class<T>.

Mas a minha mensagem você entendeu. Eu só devia ter sido mais cuidadoso e ter falado “quase todos”. :stuck_out_tongue:

[EDITADO]
Então reescrevendo:
Na época de Generics, muita gente torceu o nariz e no final quase todos viram que foi melhor.
[/EDITADO]

R

O remendo é melhor que nada, mas não é o melhor.

T

Bom, pra mim o que interessa é que agora a consistência das minhas coleções pode ser verificada em tempo de compilação, além de não ter que ficar fazendo casts o tempo todo.
Mas veja só, eu falando que a comunidade é exigente, nem tinha reparado que há uns posts atrás nesse tópico eu tava reclamando da sintaxe de closures também :oops:

M

tnaires:
Bom, pra mim o que interessa é que agora a consistência das minhas coleções pode ser verificada em tempo de compilação, além de não ter que ficar fazendo casts o tempo todo.
Mas veja só, eu falando que a comunidade é exigente, nem tinha reparado que há uns posts atrás nesse tópico eu tava reclamando da sintaxe de closures também :oops:

O cast está lá, só que agora ele se esconde atrás de um <String> e mesmo com código “genérico” é possível causar ClassCastExceptions, simplesmente porque a implementação de genericos não existe, é uma coisa que está na imaginação dos programadores Java :slight_smile:

Todas as propostas de reificação que eu vi em java quebram a compatibilidade por completo do código genérico atual e eu duvido muito que eles tenham interesse em fazer isso. Eles deveriam fazer igual a MicOsoft, admitir que a implementação é chula e escrever tudo denovo. Ou esquecer Java e começar a dar mais valor a outras linguagens da JVM, como Scala.

B

Do jeito que a coisa tá indo com o Java, só um pensamento vem a minha cabeça:

“Eu não sei com que IDEs o Java 8 será programado, mas o Java 9 será com paus e pedras.”

F

Olá senhores,

Este recurso me lembra a execução de blocos de código que existe/existiam em clipper vrs. 5.x

Evidencia 1

CLS ? EVAL( { | nVar | nVar * nVar }, 6 )

Evidencia 2

aVar := { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } bDouble := { | nVal | QOUT( TRANSFORM( ( nVal * 2 ), "@B 999")) } AEVAL( aVar, bDouble )

Evidencia 3

A := {'GARY HALL', 'FRED SMITH', 'TIM JONES'} B := { | X, Y | X > Y } asort(A, B)

Vou parar com as evidencias de utilização em clipper porque simples as formas de uso de blocos de códigos nesta linguagem deve beirar uma centena.

Me parece que na linguagem Ruby tem algo semelhante:

array = [1, 'hi', 3.14] array.each { |item| puts item }

Pois bem, este recurso já existe fazem uns 15 ou 16 anos :shock:

Causou grande repercussão na linguagem clipper na época, pelo fato dela ser procedural e este recurso permitir a construção de algoritimos mais “sofisticados” e aumentando bastante o poder das estruturas dinamicas da linguagem.

O problema é que fazer a manutenção em algoritimos construidos com este recurso do tipo “sedutor” era dramático, porque o desenvolvedor geralmente aplicava isto como solução para tudo. Posso estar errado (e quero estar) mas muitos vão esquecer da OOP e aplicar isto na primeira dificuldade que aparecer.

Talvez este recurso se encaixe bem em linguagens como Ruby porque as propostas estão (IMO) bastante relacionadas, mas isto não diminui os possíveis problemas que podem ser causados por ele.

P.S. Com certeza isso irá fazer com que novos livros ou capitulos de livros sobre melhores práticas sejam editados enchendo ainda mais os bolsos de alguns.

flw

P

E o que já está implementado? Fica pra lá?

R

Não, faz a mesma coisa que um espremedor com a laranja

L

fantomas:
Olá senhores,

Este recurso me lembra a execução de blocos de código que existe/existiam em clipper vrs. 5.x

Evidencia 1

CLS ? EVAL( { | nVar | nVar * nVar }, 6 )

Evidencia 2

aVar := { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } bDouble := { | nVal | QOUT( TRANSFORM( ( nVal * 2 ), "@B 999")) } AEVAL( aVar, bDouble )

Evidencia 3

A := {'GARY HALL', 'FRED SMITH', 'TIM JONES'} B := { | X, Y | X > Y } asort(A, B)

Vou parar com as evidencias de utilização em clipper porque simples as formas de uso de blocos de códigos nesta linguagem deve beirar uma centena.

Me parece que na linguagem Ruby tem algo semelhante:

array = [1, 'hi', 3.14] array.each { |item| puts item }

Pois bem, este recurso já existe fazem uns 15 ou 16 anos :shock:

Causou grande repercussão na linguagem clipper na época, pelo fato dela ser procedural e este recurso permitir a construção de algoritimos mais “sofisticados” e aumentando bastante o poder das estruturas dinamicas da linguagem.

O problema é que fazer a manutenção em algoritimos construidos com este recurso do tipo “sedutor” era dramático, porque o desenvolvedor geralmente aplicava isto como solução para tudo. Posso estar errado (e quero estar) mas muitos vão esquecer da OOP e aplicar isto na primeira dificuldade que aparecer.

Talvez este recurso se encaixe bem em linguagens como Ruby porque as propostas estão (IMO) bastante relacionadas, mas isto não diminui os possíveis problemas que podem ser causados por ele.

P.S. Com certeza isso irá fazer com que novos livros ou capitulos de livros sobre melhores práticas sejam editados enchendo ainda mais os bolsos de alguns.

flw

Closure não é somente passagem de função de um lugar para outro! Uma função com suporte a closure captura o contexto onde foi criado. Coisa que em linguagens procedurais não acontecia (como: VB, Clipper, C) por uma razão simples: só haviam dois contextos, o local (dentro da função) e o global. E os dois eram sempre acessados onde quer que a função fosse executada.

Em linguagem OO, existe também o contexto do objeto. E com isso, não basta criar uma função e executá-lo por aí, é necessário que esta tenha a referência do objeto que a criou. Essa obtenção de referência, é o closure!

Veja mais em http://pt.wikipedia.org/wiki/Closure .

B

Maurício Linhares:

A implementação de generics em java é sebosa e não existe informação nenhuma sobre os genéricos em tempo de execução, obrigando a construção de gambiarras (como passar o Class<T> quando você já passou T em algum lugar, não haver T[]). Uma feature que adiciona um absurdo de complexidade acidental, sem adicionar quase nada em funcionalidades. E a falta de type-inference faz o código generico ser desnecessariamente feio.

O motivo para não haver T[] é que arrays no java são covariant:

Object[] numbers = new Long[1]; numbers[0] = "ops..."; //vai ter problemas em tempo de execução...!

Para resolver esse problema use LIST, pois é invariant (só aceita mesmo tipo) e se haver algo errado nem deixa compilar.

Ou seja, isso pelo menos garante mais qualidade pro código. Eu não sei como conseguem implementar em outras linguagens estáticas o T[], a não ser que as arrays desde o começo fossem invriants, pq do contrário é improvável que admitam covariants em generics.

D

Hmmm…

F

renato3110:
Closure não é somente passagem de função de um lugar para outro! Uma função com suporte a closure captura o contexto onde foi criado. Coisa que em linguagens procedurais não acontecia (como: VB, Clipper, C) por uma razão simples: só haviam dois contextos, o local (dentro da função) e o global. E os dois eram sempre acessados onde quer que a função fosse executada.

Em linguagem OO, existe também o contexto do objeto. E com isso, não basta criar uma função e executá-lo por aí, é necessário que esta tenha a referência do objeto que a criou. Essa obtenção de referência, é o closure!

Veja mais em http://pt.wikipedia.org/wiki/Closure .

Valeu pelo esclarecimento…

Só quiz deixar claro que:

a) A idéia na minha opinião não é nova, como disse ela dever ter uns 15 anos e provavelmente o Turbo Pascal também já tinha coisa parecida (e melhor) 4 ou 5 anos antes disso, ou seja, 20 anos se não for mais rsrsrsrs.

b) Pelo fato do clipper ser procedural e java ser orientado a objetos e +15 anos terem se passado desde quando a ideia apareceu é claro que alguma coisa diferente tinha que ter.

c) Os códigos feitos com code blocks se transformaram em um inferno em termos de manutenção e conceito, e com os “closures”, na minha opinião, não será diferente. Diria que será pior porque além dos BOLOVO teremos os closures para atormentar ainda mais :frowning: .

[]'s

R

Mas não fui eu quem disse aquilo :smiley:

F

Ops! Foi mal :oops: …me desculpe, foi o Leonardo3001.

F

Não sei se é um pouco precoce perguntar isto agora, mas e o groovy como fica? Pois dentre outras coisas ele tb possui closures. Será que estas funcionalidades “dinâmicas” na jdk vão matar o groovy?

B

O Groovy fica no canto dele, sem nada a ver com a história. Nada muda.

Talvez melhorem o suporte e o conjunto de instruções da JVM, e com isso a performance de qualquer linguagem dinâmica na plataforma, mas só isso.

V

[milésima mensagem. :slight_smile: ]

Bem, desde a primeira vez que vi closures em java achei a sintaxe feia, confusa e cheia de pegadinhas e regras estranhas por debaixo dos panos (algo inerente da condição de ser uma feature tardia que obrigatoriamente teve que ser implementada com gambiarras na linguagem para não violar o backwards-compatible, a la generics).

Mas realmente, eu vi uma tendência de que closures virou modinha e tem muita gente tentando rubynizar o java usando closures só porque acha bonito, sem haver necessidade.

Há também um grande perigo na manutenção. Gambiarrizadores que produzem toneladas de código de péssima qualidade têm dificuldades com generics porque usá-los em lugar inadequado quase sempre resulta em erro de compilação, warning ou ClassCastException. Mas com closures é diferente: é possível utilizá-lo para fazer um goto dinâmico e destruir a manutenibilidade do código.

Ou seja, é um recurso poderoso e muito útil, mas também perigoso. Não deve ser usado a torto e a direito, senão vai trazer mais problemas do que resolver.

P

Isso eu achei interessante:

public class A {
        public static void main(String args[]) {
            @Shared int x = 0;

            {int, int => int } xxx  = { int a, int b =>  x += a + b ; x};

            System.out.println(xxx.invoke(3,4));
            System.out.println(xxx.invoke(2,4));

        }
}

Sem o @Shared eu recebo um warning, nada mais do que justo!

R

:oops: ainda vou entender com mais carinho as closures, ainda não entendi um uso no meu dia a dia.

Vendo o Mauricio com essa foto malvada ai acho que vou ver o Scala que só ouvir falar rsss :smiley:

eu não paro de estudar desde os meus 16 anos e to com 30 rsss, já foi tantas linguagens.

:roll:

L

hum… ja ate sei do que as proximas edições da javamagazine e mundojava iram falar…

po deveriam colocar ponteiros na linguagem… sinto falta dos ponteiros…

S

luistiagos:

po deveriam colocar ponteiros na linguagem… sinto falta dos ponteiros…

Curiosidade: Que falta eles te fazem no dia a dia ?

V

Ssalgado:
luistiagos:

po deveriam colocar ponteiros na linguagem… sinto falta dos ponteiros…

Curiosidade: Que falta eles te fazem no dia a dia ?

Acho que ele estava sendo irônico. :smiley:

F

É…também achei isso curioso.

S

victorwss:
Ssalgado:
luistiagos:

po deveriam colocar ponteiros na linguagem… sinto falta dos ponteiros…

Curiosidade: Que falta eles te fazem no dia a dia ?

Acho que ele estava sendo irônico. :smiley:

Se sim, foi mal. hehe

Se não, ainda estou curioso. :stuck_out_tongue:

P

Alguém pra falar de ponteiros em Java só pode estar sendo irônico mesmo. rs

T

Uma coisa que seria interessante em closures é se eu pudesse fazer currying também.

Não cheguei a brincar suficientemente com o protótipo final (e olhe que eu estou acompanhando isso desde as primeiras propostas do Gafter), mas eu gostaria de fazer algo semelhante ao que posso fazer no Boost:

#include &lt;boost/asio.hpp&gt;
...

boost::asio::async_read (socket, boost::asio::buffer (buf, 0, nbytes), 
    boost::bind (&MyClass::MyReadHandler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));

onde “boost::bind” é um template que efetua o currying de MyReadHandler, passando a “this” o ponteiro para função-membro “MyClass::MyReadHandler”, e então passando os parâmetros a essa função-membro: error e bytes_transferred.

F

thingol:
Uma coisa que seria interessante em closures é se eu pudesse fazer currying também.

Não cheguei a brincar suficientemente com o protótipo final (e olhe que eu estou acompanhando isso desde as primeiras propostas do Gafter), mas eu gostaria de fazer algo semelhante ao que posso fazer no Boost:
view plaincopy to clipboardprint?

  1. #include <boost/asio.hpp>
  2. boost::asio::async_read (socket, boost::asio::buffer (buf, 0, nbytes),
  3. boost::bind (&MyClass::MyReadHandler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
    

#include <boost/asio.hpp> … boost::asio::async_read (socket, boost::asio::buffer (buf, 0, nbytes), boost::bind (&MyClass::MyReadHandler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
onde “boost::bind” é um template que efetua o currying de MyReadHandler, passando a “this” o ponteiro para função-membro “MyClass::MyReadHandler”, e então passando os parâmetros a essa função-membro: error e bytes_transferred.

??? :shock: ???

P

fantomas:
thingol:
Uma coisa que seria interessante em closures é se eu pudesse fazer currying também.

Não cheguei a brincar suficientemente com o protótipo final (e olhe que eu estou acompanhando isso desde as primeiras propostas do Gafter), mas eu gostaria de fazer algo semelhante ao que posso fazer no Boost:
view plaincopy to clipboardprint?

  1. #include <boost/asio.hpp>
  2. boost::asio::async_read (socket, boost::asio::buffer (buf, 0, nbytes),
  3. boost::bind (&MyClass::MyReadHandler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
    

#include <boost/asio.hpp> … boost::asio::async_read (socket, boost::asio::buffer (buf, 0, nbytes), boost::bind (&MyClass::MyReadHandler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
onde “boost::bind” é um template que efetua o currying de MyReadHandler, passando a “this” o ponteiro para função-membro “MyClass::MyReadHandler”, e então passando os parâmetros a essa função-membro: error e bytes_transferred.

??? :shock: ???

Tambem não entendi bulhufas. Mas sei que é porque ainda não estamos no nivel Yoda, somos padawans ainda. Quero virar Jedi até o fim do ano, mas Yoda… rs… Tá dificil!

P

No aguardo de um post elucidativo e didático. :smiley:

T

Sergio Figueras:
fantomas:
thingol:
Uma coisa que seria interessante em closures é se eu pudesse fazer currying também.

Não cheguei a brincar suficientemente com o protótipo final (e olhe que eu estou acompanhando isso desde as primeiras propostas do Gafter), mas eu gostaria de fazer algo semelhante ao que posso fazer no Boost:
view plaincopy to clipboardprint?

  1. #include <boost/asio.hpp>
  2. boost::asio::async_read (socket, boost::asio::buffer (buf, 0, nbytes),
  3. boost::bind (&MyClass::MyReadHandler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
    

#include <boost/asio.hpp> … boost::asio::async_read (socket, boost::asio::buffer (buf, 0, nbytes), boost::bind (&MyClass::MyReadHandler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
onde “boost::bind” é um template que efetua o currying de MyReadHandler, passando a “this” o ponteiro para função-membro “MyClass::MyReadHandler”, e então passando os parâmetros a essa função-membro: error e bytes_transferred.

??? :shock: ???

Tambem não entendi bulhufas. Mas sei que é porque ainda não estamos no nivel Yoda, somos padawans ainda. Quero virar Jedi até o fim do ano, mas Yoda… rs… Tá dificil!

Me senti um merda agora…

R
peczenyj:
Isso eu achei interessante:
public class A {
        public static void main(String args[]) {
            @Shared int x = 0; 

            {int, int => int } xxx  = { int a, int b =>  x += a + b ; x};

            System.out.println(xxx.invoke(3,4));
            System.out.println(xxx.invoke(2,4));

        }
}

Sem o @Shared eu recebo um warning, nada mais do que justo!

Deveria ser o contrário, com o @Shared: Warning: too many gambiarras

V
renato3110:
peczenyj:
Isso eu achei interessante:
public class A {
        public static void main(String args[]) {
            @Shared int x = 0; 

            {int, int => int } xxx  = { int a, int b =>  x += a + b ; x};

            System.out.println(xxx.invoke(3,4));
            System.out.println(xxx.invoke(2,4));

        }
}

Sem o @Shared eu recebo um warning, nada mais do que justo!

Deveria ser o contrário, com o @Shared: Warning: too much gambiarras

O Shared é uma gambiarra para permitir que o closure altere o valor da variável local.

CHUTE: ACHO que isso pode ser implementado pelo compilador criando um objeto oculto no método, transformando a variável local em um atributo deste objeto oculto e fazendo tanto o método quanto o closure usar este atributo. Quando o método termina, o objeto contendo o atributo ainda existe no heap, até que o coletor de lixo o descarte.

Quando a variável é final, sem problemas. O compilador faz o mesmo que ele faz atualmente com classes anônimas. Mas quando não é, essa manobra do compilador resolve o problema.

Aliás, isso não serve apenas para closures. Pode ser usado para classes anônimas também, resolvendo o problema do "annoying final".

Daí, aquele erro de compilação de que a variável local deveria ser final se reduziria a uma warning (porque provavelmente o compilador fará algo que faz com que a variável local deixe de ser de fato apenas uma variável local). Daí o @Shared funciona mais ou menos como um @SuppressWarnings para isso.

Edit: BTW closures são reduzidos pelo compilador em classes anônimas que posteriormente são reduzidas a classes internas e por fim a classes normais com visibilidade de pacote.

B

thingol:
Uma coisa que seria interessante em closures é se eu pudesse fazer currying também.

Não cheguei a brincar suficientemente com o protótipo final (e olhe que eu estou acompanhando isso desde as primeiras propostas do Gafter), mas eu gostaria de fazer algo semelhante ao que posso fazer no Boost:

#include &lt;boost/asio.hpp&gt;
...

boost::asio::async_read (socket, boost::asio::buffer (buf, 0, nbytes), 
    boost::bind (&MyClass::MyReadHandler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));

onde “boost::bind” é um template que efetua o currying de MyReadHandler, passando a “this” o ponteiro para função-membro “MyClass::MyReadHandler”, e então passando os parâmetros a essa função-membro: error e bytes_transferred.


Isso é currying de função ou pré-configuração do objeto?

Currying em Java só no dia que tivermos objetos-Função/Bloco

M

Bruno Laturner:
Isso é currying de função ou pré-configuração do objeto?

Currying em Java só no dia que tivermos objetos-Função/Bloco

Traduzindo, quando Java tiver Closures :slight_smile:

P

public class X { public X doSomething() { /* statement */ return this; } }

Como posso criar uma closure que retorne ela mesma? Faz sentido?

S

peczenyj:
public class X { public X doSomething() { /* statement */ return this; } }

Como posso criar uma closure que retorne ela mesma? Faz sentido?

Não tenho a certeza , mas o this dentro do bloco de refere a uma instância da classe X e não ao objeto da closure.

P

Humm é mesmo, não faria muito sentido!

M

[size=13][color=blue]Uma resposta interessante para Closures[/color] [/size]

FONTE http://forums.sun.com/thread.jspa?threadID=612915&messageID=3390587

"I would still like to know what the closure abstration really means, then I will be
able to appreciate how well it is supported in a specific language like C++ or Java"

In set algebra, a closure of a set S, w.r.t. a binary operator ‘o’ is a set that contains
all elements of S and itself including the elements ‘a o b’, where a and b belong
to S or the closure of S, i.e. there are no possible elements to be found outside
this closure. e.g. mathematically, the set of all integers is a closure w.r.t. the +
operator. (the sum of two integers still is an integer).

Related to this mathematical notion is the closure of type 3 languages, or
regular expressions if you prefer. If RE is a regular expression, then RE*, i.e.
zero or more catenations of RE, is a closure of RE and is still a regular expression.

In the functional programming language world, a closure is a function where
no free variables can be found. e.g. f(x) <- x+y is not a closure, but g(y) <- f(x)
is one, if y is bound to a value. ‘Currying’ is a closely related concept.

If functions can be a first class citizen in a programming language, i.e. if functions
can be passed as arguments to other functions, just like simple ints etc, closures
are possible in that language no matter how ‘mechanical’ the construct.

In C, closures can be implemented by passed the address of a funcion and a
pointer to some struct that contains values needed by that function. The function
itself can dig those values from somewhere in that struct.

Object oriented language can ‘hide’ that fact a bit more by encapsulating those
values, as well as the function itself in an object. Languages that allow operator
overloading, including the function call ‘operator’ can hide this mechanism even
more by faking the object to be a function.

The possibilities are (almost?) endless here and it’s up to your imagination how
to fake/handle those ‘closures’. BeanShell (an interpreted Java like language) for
example allows this:

Object f() { int x= 42; void g() { System.out.println(&quot;Foo! &quot;+x); } return this; } Object o= f(); o.g();

This code snippet prints “Foo! 42”; function f() acts as a closure for function g() and
can even keep all ‘state’ for that function g().

B

Maurício Linhares:
Bruno Laturner:
Isso é currying de função ou pré-configuração do objeto?

Currying em Java só no dia que tivermos objetos-Função/Bloco

Traduzindo, quando Java tiver Closures :)

Closure c = { int, int =&gt; int } soma = { int a, int b =&gt; a + b }; Isso, ou algo parecido, é possível?

Marcio Duran:
[size=13][color=blue]Uma resposta interessante para Closures[/color] [/size]

(…)


Poste a fonte… http://forums.sun.com/thread.jspa?threadID=612915&messageID=3390587

M

FONTE

http://forums.sun.com/thread.jspa?threadID=612915&messageID=3390587

Achei que ficou melhor colocado, então postei essa fonte Sun Java Programming

T

Não há um tipo "Closure". Entretanto, você pode fazer a seguinte declaração:

{int,int =&gt; int} soma = {int a, int b =&gt; a + b };
int x = soma.invoke (2, 3); // deve retornar 5

Não lembro direito (e estou sem o protótipo aqui para testar), mas se não me engano, esses tipos são sempre interfaces, então você pode ter algo como:

class Teste implements {int, int =&gt; int}
{
    public int invoke (int a, int b) { return a + b; }
}
M

Neal Gafter Discusses Closures, Language Features and Optional Typing
Entrevista com alta resolução e texto simultaneo, InfoQ: Mais detalhes de Closures e JVM 1.7

:idea: http://www.infoq.com/interviews/gafter-closures-language-features-optional-typing

P

citando alguém mais pra cima nesse post, rola um Too much Gambiarra aí ou um Warning: Not Syntax Sugar? :smiley:

Java desempenha um papel legal de compilador para novas linguagens sob a plataforma / linguagens dinâmicas (claro que nem sempre da maneira ideal para as linguagens dinâmicas). Agora essa incorporação de comportamento não previsto anteriormente no projeto da linguagem java tá de matar. =D

T+

P

thingol:
Uma coisa que seria interessante em closures é se eu pudesse fazer currying também.

Não cheguei a brincar suficientemente com o protótipo final (e olhe que eu estou acompanhando isso desde as primeiras propostas do Gafter), mas eu gostaria de fazer algo semelhante ao que posso fazer no Boost:

#include &lt;boost/asio.hpp&gt;
...

boost::asio::async_read (socket, boost::asio::buffer (buf, 0, nbytes), 
    boost::bind (&MyClass::MyReadHandler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));

onde “boost::bind” é um template que efetua o currying de MyReadHandler, passando a “this” o ponteiro para função-membro “MyClass::MyReadHandler”, e então passando os parâmetros a essa função-membro: error e bytes_transferred.

Isso daí que o thingol quer fazer tá parecendo com essa discussão aqui

T+

V

thingol:

Closure c = { int, int => int } soma = { int a, int b =>; a + b };

Não há um tipo "Closure". Entretanto, você pode fazer a seguinte declaração:

{int,int =&gt; int} soma = {int a, int b =&gt; a + b };
int x = soma.invoke (2, 3); // deve retornar 5

Não lembro direito (e estou sem o protótipo aqui para testar), mas se não me engano, esses tipos são sempre interfaces, então você pode ter algo como:

class Teste implements {int, int =&gt; int}
{
    public int invoke (int a, int b) { return a + b; }
}

Sim, surgirá uma quantidade infinita de interfaces dentro do pacote javax.lang.function correspondentes aos closures. Uma bela gambiarra no compilador!

S

Admitindo que isso é possível ( o que me parece que não seja, mas tb não testei) estaria no mesmo nivel de codigos como

O objetido de um tipo de função (Function Type) é conter codigo, aka é o corpo entre chaves em um objeto ( já que e´a única coisa em java que não é uma objeto … além dos primitivos, mas esse já têm o auto-boxing)
Tipo de função são apenas um boxing de codigo. Desde ponto de vista não ha razão para tentar escrever o código acima (até porque é “boxing” duplo ) e acredito que seria um anti-pattern pelo simples motivo que não é logico

De outro ponto de vista tipos de função ( de que as closures são um sub-tipo) não são interfaces, são objetos. São objetos que implementam certas interfaces. Mas tanto as interfaces como os objetos são criadas em runtime , logo, elas nem existem em tempo de compilação o que levaria esse código a não compilar. ( como disse não testei, mas se funcionar não faz sentido algum…)

B

invoke em que ser chamado explicitamente?

Acho sacanagem ter que fazer soma.invoke(2,3) em vez de soma(2,3). Se closures são funções, ajam como tal.

T

Ainda acho mais claro usar “soma.invoke (2, 3)” que “(*soma) (2, 3)” - que é o caso do C quando usamos ponteiros de função. (Em C++ pode-se usar (*soma) (2, 3) ou soma (2, 3) mas C++ tem 200 jeitos de fazer a mesma coisa, e um menos intuitivo que o outro).

Mas realmente é uma gambiarra que existe porque a alternativa mais intuitiva (usar “soma (2, 3)”), segundo o sr. Neal Gafter, tem alguns problemas de ambigüidade sintática que são difíceis de resolver.

S

Bruno Laturner:
invoke em que ser chamado explicitamente?

Acho sacanagem ter que fazer soma.invoke(2,3) em vez de soma(2,3). Se closures são funções, ajam como tal.

A meu ver ai é que tá a sacada… closures são objetos. “funções puras” continuam não existindo.

Imagine que vc passa uma função com parametro de um método tipo assim

<T> void doSomething(List<T> list, { T=> void} function ) {

    for (T t : list){
         function.invoke(t);
   }
}

Se vc não tiver o invoke, como executaria a função em cima de cada t ?
Algo como function(t) implicaria que function é um método da classe, o que não é verdade.

B

sergiotaborda:
Se vc não tiver o invoke, como executaria a função em cima de cada t ?
Algo como function(t) implicaria que function é um método da classe, o que não é verdade.

Respondendo ambos ao mesmo tempo:

Resolvemos da mesma forma que fazemos com atributos do objeto e variáveis locais, ambos com o mesmo identificador, usando escopo.

Edit: A questão não é “não ter invoke”, é ele não ser a única opção.

S

Bruno Laturner:

Respondendo ambos ao mesmo tempo:

Resolvemos da mesma forma que fazemos com atributos do objeto e variáveis locais, ambos com o mesmo identificador, usando escopo.

Edit: A questão não é “não ter invoke”, é ele não ser a única opção.

Tudo bem que não seja a única opção. Mas existem opções melhores que outras…
Não entendi como o escopo poderia ajudar no exemplo que dei. Explique melhor essa ideia.

L

peczenyj:
public class X { public X doSomething() { /* statement */ return this; } }

Como posso criar uma closure que retorne ela mesma? Faz sentido?

Usa o Y Combinator.

B

function() não seria o método da classe, seria a função mais próxima definida no escopo.

É um problema para visualizar isso na hora da manutenção? Bem, sim.

C

Na maioria das linguagens com caracteristicas funcionais esse exemplo do filtro e possivel em 1 linha de codigo. Passa ser mais importante entao a sintaxe da linguagem. Neste aspecto Ruby nao e das piores mas acho que poderia ser melhor.

editado: onde escrevi sintaxe queria dizer na verdade ‘expressividade’.

C

louds:
peczenyj:
public class X { public X doSomething() { /* statement */ return this; } }

Como posso criar uma closure que retorne ela mesma? Faz sentido?

Usa o Y Combinator.

Agora boiei tb.

Primeiro nao entendi porque uma funcao se daria ao trabalho de retornar ela mesma. Eu fico imaginando passar ou receber essa funcao e alguem precisar executa-la para que retorne a propria (digo ja enclosured).

Y Combinator eu sei apenas que e pra criar funcoes recursivas… mas como nao consegui entender o problema muito menos consegui ligar com a solucao. :slight_smile:

Talvez fizesse mais sentido uma funcao (e nao uma closure) que retornasse ela mesma…

F

Alguém pode me dar um exemplo prático de, como closures poderia resolver um problema, o qual não o consegueriamos sem ele?
Só para eu entender onde realmente eu poderia empregá-lo…

D

Muita gente passa a vida inteira sem sentir a menor falta delas. Closures, da maneira que estamos nos referindo aqui é uma maneira de usar higher order procedures, que nos permitem ‘aumentar’ nosso poder de abstração e a expressividade dos nossos programas. Aqui tem um ótimo exemplo de como expressar derivadas usando high order procedures, é menos complicado do que parece.

L

cmoscoso:

Agora boiei tb.

Primeiro nao entendi porque uma funcao se daria ao trabalho de retornar ela mesma. Eu fico imaginando passar ou receber essa funcao e alguem precisar executa-la para que retorne a propria (digo ja enclosured).

Y Combinator eu sei apenas que e pra criar funcoes recursivas… mas como nao consegui entender o problema muito menos consegui ligar com a solucao. :slight_smile:

Talvez fizesse mais sentido uma funcao (e nao uma closure) que retornasse ela mesma…

O YC permite a função ter uma referencia a si própria, agora se ela vai se chamar recursivamente ou simplesmente retornar o valor é indiferente.

C

louds:

O YC permite a função ter uma referencia a si própria, agora se ela vai se chamar recursivamente ou simplesmente retornar o valor é indiferente.

Louds, vc tem razao,

E pq ando lendo sobre cultura lisp onde closures sao implementadas na linguagem desde sempre pra trabalhar com funcoes anonimas.

Mas pensando melhor sobre nomenclatura em outras linguagens onde closures sao implementadas posteriormente, talvez seja melhor mesmo falar “retornar uma closure”, pra diferenciar de outro mecanismo utilizado ate entao pela linguagem para passar/retornar blocos de codigo (classes internas anonimas em Java). Parece que em lisp essa diferenciacao nao é importante do ponto de vista pro programador.

O que vc acha?

P

facholi:
Alguém pode me dar um exemplo prático de, como closures poderia resolver um problema, o qual não o consegueriamos sem ele?
Só para eu entender onde realmente eu poderia empregá-lo…

Da mesma forma que não existe problema que OO resola que não seja resolvido antes você não vai encontrar um exemplo destes. A questão é apenas a maneira como resolvemos.

L

cmoscoso:
louds:

O YC permite a função ter uma referencia a si própria, agora se ela vai se chamar recursivamente ou simplesmente retornar o valor é indiferente.

Louds, vc tem razao,

E pq ando lendo sobre cultura lisp onde closures sao implementadas na linguagem desde sempre pra trabalhar com funcoes anonimas.

Mas pensando melhor sobre nomenclatura em outras linguagens onde closures sao implementadas posteriormente, talvez seja melhor mesmo falar “retornar uma closure”, pra diferenciar de outro mecanismo utilizado ate entao pela linguagem para passar/retornar blocos de codigo (classes internas anonimas em Java). Parece que em lisp essa diferenciacao nao é importante do ponto de vista pro programador.

O que vc acha?

Acho que levará bastante tempo até a comunidade realizar o poder do que é possível com closures.

Vejo isso pelo .NET. As pessoas ainda estão explorando muito o C# 3.0.

T

O problema do Java é que ele ficou “institucionalizado” - é uma linguagem didática e comercial, como se fosse um Cobol moderno (sempre que quero chocar um Java-maníaco, digo para ele que “Java == COBOL”).
E é por isso que acabam se opondo às mudanças; como se sabe, é mais difícil fazer uma mudança que não destrua tudo que já foi feito - como foi o caso do “generics”, que tentou ser retrocompatível com os programas antigos e ficou extremamente difícil de entender - que uma mudança que destrua tudo (como é o caso de cada versão do C# que aparece).
A nova mudança (closures), que tem de ser retrocompatível com os programas antigos, também é difícil de entender, e fica um pouco abaixo das expectativas - se a Sun simplesmente fosse a única dona do Java, e ela se notabilizasse por destruir tudo que foi feito antes - o que não é bem o que a Sun faz; programas antigos em C que rodam em antigas máquinas Sparc continuam rodando nas novas de hoje em dia sem problemas - então ela poderia fazer algo mais simples, como o que apareceu no C# 3.0.
O Neal Gafter, embora não trabalhe mais para a Sun, compreende o que deve ser feito para não afetar os programas antigos, e é por isso que a parte de Closures é menos ambiciosa e mais complicada do que ela poderia ser.

C

Pro Louds:
Sera que os programadores nao explorarao o poder de closures em Java por falta de ambicao na implementacao (o thingol colocou como ‘a coisa certa’, ignorar compatibilidade retroativa) ou por que os proprios programadores nao conhecem tecnicas de programacao funcional?

Pro Thingol:
Deve ter sido mesmo um trabalho do cao pra implementar closures em Java mas vc acha mesmo que a interface ficou tao ruim ao ponto de ser pior pra entender do que todas aquelas regrinhas especificas do uso de classes internas, sintaxe fora do convencional para classes anonimas, ter que declarar variaveis final?

A minha opiniao é que sim, simplicidade na implementacao importa mas compatibilidade tb é importante ate certo ponto.

“Java == COBOL Moderno”, vc disse tudo aqui, eu tenho a mesma impressao mas… isso é necessariamente algo ruim?

Apenas se Java for sua unica opcao para tudo.

M

sergiotaborda:
[Bruno Laturner]invoke em que ser chamado explicitamente?

Acho sacanagem ter que fazer soma.invoke(2,3) em vez de soma(2,3). Se closures são funções, ajam como tal.

Segundo autor da fonte confiável, “Anonima” vou colocar aqui a resposta que achei plausível.

“Closure não será incorporado pela linguagem (pelo menos em Java 7) segundo palavras do próprio Mister M (Michael Nascimento) e mesmo na comunidade internacional, houve uma arrefecida desse tópico.”

Agora segundo, anonimo, ai vem a resposta !!!

A sua afirmação sobre uma forma de se declarar uma classe simplificada que possuirá apenas uma função não deixa de ser verdade no contexto de Java.A primeira utilização seria para contemplar um problema que a comunidade java reclama, a verborragia da linguagem.

Seria melhor fazer isso:

import java.util.ArrayList; 
import java.util.Collections; 
import java.util.Comparator; 
import java.util.List; 


public class Teste{ 
    public static void main(String[] args){ 
          List<Endereco> l = new ArrayList<Endereco>(); 
          l.add(new Endereco("Rua dos Batatais",327)); 
          l.add(new Endereco("Rua das Cebolas",127)); 
          
          Collections.sort(l,new Ordenador()); 
          for (Endereco endereco : l) { 
            System.out.println(endereco.getRua()); 
        } 
    } 
}

ou isso (usando a notação proposta pelo Neal Gafter)?

import java.util.ArrayList; 
import java.util.Collections; 
import java.util.Comparator; 
import java.util.List; 


public class Teste{ 
    public static void main(String[] args){ 
          List<Endereco> l = new ArrayList<Endereco>(); 
          l.add(new Endereco("Rua dos Batatais",327)); 
          l.add(new Endereco("Rua das Cebolas",127)); 
         int(Object, Object) funcao = (Object e1, Object e2){ 
                                            return ((Endereco)o1).getNumero()-((Endereco)o2).getNumero(); 
                                      }; 
          Collections.sort(l,funcao); 
          for (Object o : l) { 
            System.out.println(((Endereco)o).getRua()); 
        } 
    } 
}

–Classe Endereco usada acima –

public class Endereco { 

    private String rua; 
    private int numero; 

    public Endereco(String string, int i) { 
        this.rua = string; 
        this.numero = i; 
    } 

    String getRua() { 
        return rua; 
    } 

    void setRua(String rua) { 
        this.rua = rua; 
    } 

    int getNumero() { 
        return numero; 
    } 

    void setNumero(int numero) { 
        this.numero = numero; 
    } 

}

PS: haveria uma nova sobrecarga no Collections.sort, para aceitar uma “função”

Essa seria então a idéia inicial: Criar um açúcar sintático eliminando a regra de que tudo tem de ser uma classe em java(nesse contexto, “explodimos” uma das regras de Ouro em Java).

Isso é bom, por limpar a quantidade código digitada pelo desenvolvedor, mas essa seria a resposta mais simplória.

O uso de closures não é apenas isso. Ele é muito mais do que isso!

Se Java aceitar tal facilidade do jeito que foi concebida, e suportar o método invoke que utilizou no código abaixo nós teremos uma das qualidades mais interessantes que uma linguagem ofereceria: a injeção de código em lacunas a serem preenchidas pelos desenvolvedores.

Design patterns como o Template, não precisariam ser implementados da maneira que existe em muitos frameworks em Java (exemplo classico é o que Struts faz).

.NET caminhou para esse lado, ao suportar os métodos anônimos (anonymous methods) e que oferece atualmente o LinQ, que é uma maneira de acessa a camada de dados de maneira transparente.

Outro ponto, bem citado pelo Joel Spolsky e é bem verdade, está no seguinte link:

V

O que acontece é que as classes eliminadas neste caso são boilerplates em forma de classes (frequentemente anônimas) que não representam nenhuma entidade real do sistema e estão lá apenas por conta de limitações da linguagem. Ou seja, não ocorre nenhuma explosão da OO, e sim flexibilização da linguagem que acaba por abstrair a necessidade de criar-se uma classe específica para um trabalho.

S

Essa regra de ouro eu não conheço. Nem tudo é objeto em java. int, long .etc não são objetos.

S

Ssalgado:
Marcio Duran:

Essa seria então a idéia inicial: Criar um açúcar sintático eliminando a regra de que tudo tem de ser uma classe em java(nesse contexto, “explodimos” uma das regras de Ouro em Java).

Essa regra de ouro eu não conheço. Nem tudo é objeto em java. int, long .etc não são objetos.

Java é uma linguagem fortemente orientada a objetos e tipos. Todas as estruturas são objetos.
int,long etc… não são estruturas. Mas os primitivos são exceções ha regra introduzidos apenas por questões de performance e limitação (lembre-se que Java foi criado originalmente para setop boxes com ambientes limitados. isso fico enrraizado na linguagem e o objetvo continua válido ainda hoje. )
Por isso em java temos tipos primitivos e objetos. Objetos por principio e primitivos por questões tecnicas de performance , etc…

Agora, introduzindo um novo tipo chamado “função” ele seria primitivo ou objeto ?

O ponto é que Java tem as suas estruturas amarradas como objetos. Então ,sendo uma função uma estrutura ela deveria ser um objeto. Se ela não for ela será um primitivo. Mas ser um primitivo viola a regra de que apenas os primitivos são primitivos e o resto são objetos. Por outro lado estariamos confiando que uma função é um tipo especial de primitivo já que não ha promoção entre int e function, mas ha entre int e double, por exemplo. Então a escolha recai logicamente em que função tem que ser um objeto.
E é isso que os Function Types são. Objetos que implementam interfaces especiais. Primitivos continuam sendo primitivos e o resto são objetos.

Porderiamos abrir um terceiro tipo e java passaria a ter primitivos, objetos e funções.
Sendo que primitivo é uma exceção a objeto , função seria uma exceção a ambos. Isso trás vários problemas tecnicos e até fiolosoficos. A escolha de tornar função objetos é simples, clara e de acordo com a politica usada até agora. Até anotations são objetos. E repare que eles são completamente intropectivos ( não pdoe dar um new em annotation). function type segue o mesmo caminho.

L

Isso não é verdade. A distinção existe por pura incompetência dos designers da linguagem e máquina virtual. A CLR não possui qualquer forma de tipo primitivo
e tem performance na mesma categoria do Java. Alimentar um mito envolva desses erros é um enorme desserviço a todos aqui no GUJ.

Essa discussão de primitivo ou objeto é enraizada na ignorância da distinção entre ambos.
Não faz sentido argumentar em cima disso quando, fundamentalmente, deveriam questionar sobre
quais carregam semântica de value type/scalar ou reference type.
Pois está a distinção dos tipos em Java rotulados de primitivos por falha dos designers da linguagem.

Curiosamente, esta é uma exigência feita a mais de uma década para a Sun, suportar tipos escalares
arbitrários.

sergiotaborda:

O ponto é que Java tem as suas estruturas amarradas como objetos. Então ,sendo uma função uma estrutura ela deveria ser um objeto. Se ela não for ela será um primitivo. Mas ser um primitivo viola a regra de que apenas os primitivos são primitivos e o resto são objetos. Por outro lado estariamos confiando que uma função é um tipo especial de primitivo já que não ha promoção entre int e function, mas ha entre int e double, por exemplo. Então a escolha recai logicamente em que função tem que ser um objeto.
E é isso que os Function Types são. Objetos que implementam interfaces especiais. Primitivos continuam sendo primitivos e o resto são objetos.

Porderiamos abrir um terceiro tipo e java passaria a ter primitivos, objetos e funções.
Sendo que primitivo é uma exceção a objeto , função seria uma exceção a ambos. Isso trás vários problemas tecnicos e até fiolosoficos. A escolha de tornar função objetos é simples, clara e de acordo com a politica usada até agora. Até anotations são objetos. E repare que eles são completamente intropectivos ( não pdoe dar um new em annotation). function type segue o mesmo caminho.

Seu questionamento é completamente descabido. Pois uma closure é isomorfa a um tipo por referência, a um objeto. Anotações são tipos comuns a linguagem e a questão
de poderem ser usadas para anotar membros é ortogonal, elas são apenas uma categoria particular de interfaces.

Sérgio, por favor, faça sua lição de casa antes de sair disseminando desinformação.

S

louds:
sergiotaborda:

Java é uma linguagem fortemente orientada a objetos e tipos. Todas as estruturas são objetos.
int,long etc… não são estruturas. Mas os primitivos são exceções ha regra introduzidos apenas por questões de performance e limitação (lembre-se que Java foi criado originalmente para setop boxes com ambientes limitados. isso fico enrraizado na linguagem e o objetvo continua válido ainda hoje. )
Por isso em java temos tipos primitivos e objetos. Objetos por principio e primitivos por questões tecnicas de performance , etc…

Isso não é verdade. A distinção existe por pura incompetência dos designers da linguagem e máquina virtual. A CLR não possui qualquer forma de tipo primitivo

Devo compreender das suas palavras que vc só usa Long, Integer, Boolean, Double , etc… nos seus programas ? e nunca long, int , boolean , double ?
Devo compreender das suas palavras que escreve ifs assim :

if (a.booleanValue()){

// do something
}

Vc quer descer em um nivel que não estava na mensagem que respondi.

louds:

Chame o que quiser. Mas quando vc faz :

Annotation x;

e usa reflection para obter x , x não é um tipo primitivo. Da mesma forma que function type também não é tipo primitivo. Esse era o ponto. A regra de ouro citada é exatamente essa “apenas os primitivos são primitivos”.
Que o mesmo que dizer que “em java tudo são objetos”. A exceção - sendo um erro ou não - é uma exceção à regra.

Criado 8 de agosto de 2008
Ultima resposta 24 de ago. de 2008
Respostas 95
Participantes 30