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/.
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 ?
D
David
Tiago, use o javac e o java que vêm no arquivo disponibilizado pelo Neal Gafter.
P
Paulo_Silveira
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
peczenyj
Putz, rateei no mais obvio... consegui rodar o primeiro exemplo sim, muito legal!!!!
public static int doIt({ int, int => int } closure){
return closure.invoke(3,2);
}
Ou isso:
Um pouco menos chato, concorda ?
T
tnaires
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 ).
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 => 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
peczenyj
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
tnaires
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
renatosilva
Acho que será mais comum fazer algo desse tipo:
public static int doIt({ int, int => 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
tnaires
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
onolox
Pela madrugada, java está se tornando uma linguagem extra-terrestre, daqui a pouco so os ETs vão entender isso.
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:
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
marcosalex
"
P
Proteu_Alcebidiano
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
Mauricio_Linhares
Poderíamos migrar todos pra Scala e sermos felizes para sempre
T
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.
R
renatosilva
Porque em vez de ficar fazendo remendos eles não criam algo novo do zero? :?
M
Mauricio_Linhares
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
tnaires
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”.
[EDITADO]
Então reescrevendo:
Na época de Generics, muita gente torceu o nariz e no final quase todos viram que foi melhor.
[/EDITADO]
R
renatosilva
O remendo é melhor que nada, mas não é o melhor.
T
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:
M
Mauricio_Linhares
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
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
Bruno_Laturner
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
fantomas
Olá senhores,
Este recurso me lembra a execução de blocos de código que existe/existiam em clipper vrs. 5.x
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
Popeye12345
E o que já está implementado? Fica pra lá?
R
renatosilva
Não, faz a mesma coisa que um espremedor com a laranja
L
Leonardo3001
fantomas:
Olá senhores,
Este recurso me lembra a execução de blocos de código que existe/existiam em clipper vrs. 5.x
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!
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
dango
Hmmm…
F
fantomas
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!
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 .
[]'s
R
renatosilva
Mas não fui eu quem disse aquilo
F
fantomas
Ops! Foi mal :oops: …me desculpe, foi o Leonardo3001.
F
fausto
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
Bruno_Laturner
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
victorwss
[milésima mensagem. ]
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.
Sem o @Shared eu recebo um warning, nada mais do que justo!
R
rufostec
: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
eu não paro de estudar desde os meus 16 anos e to com 30 rsss, já foi tantas linguagens.
:roll:
L
luistiagos
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
Ssalgado
luistiagos:
po deveriam colocar ponteiros na linguagem… sinto falta dos ponteiros…
Curiosidade: Que falta eles te fazem no dia a dia ?
V
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.
F
fantomas
É…também achei isso curioso.
S
Ssalgado
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.
Se sim, foi mal. hehe
Se não, ainda estou curioso.
P
Popeye12345
Alguém pra falar de ponteiros em Java só pode estar sendo irônico mesmo. rs
T
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:
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
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?
#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
Popeye12345
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?
#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
peczenyj
No aguardo de um post elucidativo e didático.
T
TangZero
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?
#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!
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
Bruno_Laturner
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:
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
Mauricio_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
P
peczenyj
public class X {
public X doSomething() { /* statement */ return this; }
}
Como posso criar uma closure que retorne ela mesma? Faz sentido?
S
sergiotaborda
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
peczenyj
Humm é mesmo, não faria muito sentido!
M
Marcio_Duran
[size=13][color=blue]Uma resposta interessante para Closures[/color] [/size]
"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:
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
citando alguém mais pra cima nesse post, rola um Too much Gambiarra aí ou um Warning: Not Syntax Sugar?
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
Proteu_Alcebidiano
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:
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.
Sim, surgirá uma quantidade infinita de interfaces dentro do pacote javax.lang.function correspondentes aos closures. Uma bela gambiarra no compilador!
S
sergiotaborda
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
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.
T
thingol
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
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.
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
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
Bruno_Laturner
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
sergiotaborda
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
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.
B
Bruno_Laturner
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
cmoscoso
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
cmoscoso
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.
Talvez fizesse mais sentido uma funcao (e nao uma closure) que retornasse ela mesma…
F
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…
D
dlt
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
louds
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.
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
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?
P
pcalcado
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
louds
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
thingol
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
cmoscoso
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
Marcio_Duran
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:
importjava.util.ArrayList;importjava.util.Collections;importjava.util.Comparator;importjava.util.List;publicclassTeste{publicstaticvoidmain(String[]args){List<Endereco>l=newArrayList<Endereco>();l.add(newEndereco("Rua dos Batatais",327));l.add(newEndereco("Rua das Cebolas",127));Collections.sort(l,newOrdenador());for(Enderecoendereco:l){System.out.println(endereco.getRua());}}}
ou isso (usando a notação proposta pelo Neal Gafter)?
importjava.util.ArrayList;importjava.util.Collections;importjava.util.Comparator;importjava.util.List;publicclassTeste{publicstaticvoidmain(String[]args){List<Endereco>l=newArrayList<Endereco>();l.add(newEndereco("Rua dos Batatais",327));l.add(newEndereco("Rua das Cebolas",127));int(Object,Object)funcao=(Objecte1,Objecte2){return((Endereco)o1).getNumero()-((Endereco)o2).getNumero();};Collections.sort(l,funcao);for(Objecto:l){System.out.println(((Endereco)o).getRua());}}}
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
victorwss
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
Ssalgado
Essa regra de ouro eu não conheço. Nem tudo é objeto em java. int, long .etc não são objetos.
S
sergiotaborda
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
louds
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
sergiotaborda
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()){
//dosomething
}
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.