Quem acha que Generics é a coisa mais idiota do Java 5.0?

30 respostas
louds

Junta uma implementação que é mais gambiarra que as soluções já existentes, uma justificativa que acabou virando uma mentira. Mais corner-cases que casos comuns. Sintaxe para usos mais avançados lembra templates do c++, para quem não conhece, leia confusa, complexa e pouco intuitiva.

Toda a porcaria que Generics são se deve ao fato da Sun querer manter compatibilidade com versões anteriores e não alterar o bytecode gerado. No final das contas mudaram o formato e não temos como programar com generics para java 1.4.

Erasure gera uma quantidade de corner-cases tão grande que eu não vejo vantagens em usar alêm daquilo que a biblioteca prove.

Generics são uma bomba?

30 Respostas

kuchma

Quanto aos generics, nao fui a fundo. De momento achei particularmente meio inutil o lance de static imports.

Marcio Kuchma

pcalcado

generics são elgais, agora os programadores C++ não tem o que falar. Ah, ele é só açúcar sintático? Não rola reflection direito?

:roll:

É,

[size=“24”]_o/[/size]

[]s

T

É sempre assim, quando as pessoas têm medo de mexer em alguma coisa.
Em vez de tomar uma decisão corajosa, como o pessoal do .NET :lol!: (a parte de generics foi construída “em paralelo” à infraestrutura já existente, então temos List, que é igual à nossa velha conhecida java.util.List, e GenericList<>, que é igual à nova java.util.List<>, se não me engano), fizeram uma solução que é basicamente para “autocasting”. A única coisa interessante é a parte do “foreach”.
Por exemplo, percorrer os pares chave-valor retornados por java.lang.System.getenv() em J2SE 5.0 é agora bastante fácil:

for (Map.Entry<String,String> env : System.getenv().entrySet()) { System.out.println (env.getKey() + "=" + env.getValue()); }

A parte mais chata é descobrir a declaração certa da variável “env” no código acima, devido aos “generics”. O programa acima, sem o “foreach”, é meio complicado (meio é modo de dizer)

for (Iterator<Map.Entry<String,String>> it = System.getenv().entrySet().iterator(); it.hasNext(); ) { Map.Entry<String,String> entry = it.next(); System.out.println (env.getKey() + "=" + env.getValue()); }

A declaração de "it’ é meio complicada (meio é modo de dizer), só para evitar o cast em Map.Entry<String,String> entry = it.next();, que nos velhos tempos seria apenas Map.Entry entry = (Map.Entry) it.next();

louds

“pcalcado”:
generics são elgais, agora os programadores C++ não tem o que falar. Ah, ele é só açúcar sintático? Não rola reflection direito?
[]s

Não rola reflection, não rola coisas básicas que eu não acreditei quando soube que não teria.

public class BeanFactory<T> {
   public T newInstance() {
     return new T();
   }
}

Fiquei muito puto quando soube que isso não rola.
Se tivessemos todo poder dos templates do c++ sem meta-programação com suporte total via reflection, teriamos uma ferramenta muito poderosa e não 1 ninho de vespas como vai ser…

T

A parte de “metadata” parece que vai ser de alguma valia. Nisso eles não tiveram de mexer em bytecodes, mas a JVM precisa ser atualizada para entender direito essa parte de metadata. Mas isso foi mais ou menos copiado do .NET (só que o conceito do .NET foi um pouco ampliado, já que temos vários tipos de “anotações”, não só de “tempo de execução” como é o caso do .NET).

saoj

Acredito que Generics é uma solução no vazio, uma perda de tempo. Tentaram solucionar um problema inexistente, pelo menos para mim. Poluiram a sintaxe da linguagem a troco de quê?

Se alguém conseguir me explicar as reais vantagens disso ficarei bastante contente.

Seria economizar casting ??? Acho que não, pois o bytecode precisa ser compatível com as VMs anteriores.

Seria evitar ClassCastExceptions dentro de uma collection ??? Acho que não pois se o cara quer uma lista de um objeto só, então use um array, ou extenda a lista para só aceitar esse tipo de objeto.

Deve haver alguma situação muito particular onde isso é vantajoso, mas não justifica alterar a parada toda só por causa dessa situação incomum.

Whatever…

pcalcado

“saoj”:

Seria economizar casting ??? Acho que não, pois o bytecode precisa ser compatível com as VMs anteriores.

O velho açúcar sintático, economiza pro programador…

[]s

saoj

“pcalcado”:
O velho açúcar sintático, economiza pro programador…

Hehehe. Entendi, economiza digitação para o programador, depois que algum condenado digitou toda a maluquice dos Generics na API.

A economia que eu me referia era o tempo que a VM gasta para fazer um cast de um objeto, que eu acho é bem pequeno.

Com Generics o casting seria desnecessário SE O BYTE CODE NÃO ESTIVESSE SENDO GERADO COM O CASTING PARA SER COMPATÍVEL COM AS OUTRAS VMS !!!

Não é isso que acontece ???

Luca

Olá

Há muitos meses atrás detonei os generics achando que complicam a leitura do código em troca de pouca vantagem. Só estou reafirmando a mesma opinião aqui porque sei que o louds que abriu este tópico estudou muito o uso de generics e não levantou esta lebre atoa.

Particularmente não me vejo em uma equipe que use generics nos próximos 2 ou 3 anos que é o tempo mínimo para alguém simplificar seu uso para o programador normal. Até lá já estaremos com Java 6.0 com outras coisas realmente úteis.

[]s
Luca

louds

A especificação de Generics diz que ela não deveria diminuir a performance do código em mais que 5%.

saoj

Então diminui ao invés de aumentar !!!??? Putz, que ótimo!

Essa parada que eu falei do casting faz sentido, louds? Ou seja, no bytecode o Generics some e entra o casting ?

louds

Não, com Generics os castings somente apenas do código.
O bytecode gerado é quase igual ao gerado hoje para um código sem generics.

T

Como disse é um “automatic casting”.
Uma coisa que achava muito legal em Java, no começo, é que você lia o código e sabia exatamente o que estava acontecendo (diferentemente do C++, que pode criar um monte de objetos e destruí-los sem você saber direito o que está acontecendo, até que uns 5 anos mais tarde, você consegue saber todas as regras de escopo, criação e destruição de objetos, operadores e outras coisas mais cabeludas).
Agora está ficando igual ao C++. Por exemplo, isto aqui:

Map<String,String> m = new TreeMap<String,String>();
s.put ("josé", "serra");
s.put ("marta", "suplicy");
String s = m.get("josé");

é equivalente em bytecodes ao seguinte código (basta ver o que o seu compilador gerou com javap, já que o jad não está funcionando direito ainda com o J2SE 5.0):

Map m = new TreeMap();
s.put ("josé", "serra");
s.put ("marta", "suplicy");
String s = (String) m.get("josé");

ou seja, tem um cast “automático” na linha onde pergunto o sobrenome do “josé”. Grande coisa. Mas isso pode dar algum problema porque casts são sempre casts, codificados ou não (e sempre lançam ClassCastException…)
Outra coisa “automática” que é uma droga é o “static import”. Quando criarem uma versão do Checkstyle ou PMD que suporte o J2SE 5.0 vou sugerir que todos os “static import” sejam tratados como “warnings”.
Mas para não dizer que tudo que é automático é uma droga, o “foreach” é muito legal, e os “annotations” (metadata) também são muito legais.

louds

Os cast automáticos não seriam problema se Generics fosse typesafe mesmo.

pcalcado

“saoj”:
“pcalcado”:
O velho açúcar sintático, economiza pro programador…

Hehehe. Entendi, economiza digitação para o programador, depois que algum condenado digitou toda a maluquice dos Generics na API.

Na verdade não exatamente, se alguém digitasse ot reco todo uma vez e todos reutilizassem, ia ser o máximo. Eu estava falando de JVM também, casts que poderiam ser evitados.

A compatibilidade retroativa sempre foi um grande problema quando seguido cegamente, semrpe foi assim… Sinceramente, generics como estão não acrescentam nada além de mais sintaxe bizarra para ser debugada.

E lá vamos nós aqui no GUJ com aqueles [ code ] de quinze mil linhas cheios de < e >…

[]s

louds

Não tenho muito problema com a sintaxe dos generics, mas isso se deve a eu vir do c++.
Eu acho ruim apenas que eles vão tornar java uma linguagens com tipagem fraca.

pcalcado

“louds”:
Não tenho muito problema com a sintaxe dos generics, mas isso se deve a eu vir do c++.
Eu acho ruim apenas que eles vão tornar java uma linguagens com tipagem fraca.

Eu também trabalho com C++, é aceitável diminuir a legibilidade do código quando se tem benefícios como os dos containers, mas colocar símbolos a mais numa linguagem por açúcar sintático é piada!

Mas, falando em C++ e já que comecei com citações…

Essas são do Unix Haters Handbook :slight_smile:

Hempx

Tbm entendi isso não…
Pensei que usando Generics ficaria mais rapido. Pq evitaria os cast, sendo que o compilador ao ver o uso de generics, ele substituiria uma estrutura de dados generica por uma de interesse do programador. Evitando cast e evitando redigitação de codigo…
Resumindo:(Pelo menos o que eu lembro de generics em C++) Ele apenas economizava eu redigitar um codigo todo, fazendo isso automaticamente. Ex: Eu implementaria uma pilha usando uma estrutura de dados generica. E na hora que o compilador fosse compilar meu programa ele realmente mudaria a estrutura de dados generica pela minha(int, double…). Como se ele redigitasse realmente o codigo, e tornando mais rapido tbm pq nao precisarei de usar herança igual é no java hoje em dia.

Eu acho que se funcionasse igual no C++, a propria API do Java teria muito a ganhar com generics. Mas realmente desse jeito… :evil: :evil:

ozielneto

Independente de performance ou outras considerações, a clareza de código ficou prejudicada, permitindo que programadores façam códigos ilegíveis na velocidade da luz…

[]'s

T

Só ver o javadoc de java.util.Collections.max…

max
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
Returns the maximum element of the given collection, according to the natural ordering of its elements. All elements in the collection must implement the Comparable interface. Furthermore, all elements in the collection must be mutually comparable (that is, e1.compareTo(e2) must not throw a ClassCastException for any elements e1 and e2 in the collection).

Antes era bem mais fácil de entender:


max
public static Object max(Collection coll)
Returns the maximum element of the given collection, according to the natural ordering of its elements. All elements in the collection must implement the Comparable interface. Furthermore, all elements in the collection must be mutually comparable (that is, e1.compareTo(e2) must not throw a ClassCastException for any elements e1 and e2 in the collection).
This method iterates over the entire collection, hence it requires time proportional to the size of the collection

A versão nova, com generics, parece com o STL do C++. Eu até consigo entender (obviamente uso o javadoc da versão 1.4 como “cola”… :wink: ) , mas quem mais vai conseguir entender isso? Vou ter de escrever um artigo “Generics e Collections: o que (não) mudou com o Java 5.0”

Só tomando um café…

A

Essa eu não entendi. O objetivo do generics é melhorar a checagem estática (em tempo de compilação) dos tipos. O que muita gente acha ruim (inclusive eu) é que é somente esse o objetivo.

E pelo que eu entendi o efeito na performance deveria ser nulo, porque o compilador simplesmente remove os parâmetros de tipo (erasure) e insere os casts nos lugares apropriados. Como alguém disse, é basicamente um “autocasting”. E para finalidade tão limitada eles complicaram enormemente a sintaxe da linguagem :x .

Uma discussao interessante ocorreu numa série de posts do blog do Bruce Eckel (o autor do Thinking in Java):
http://mindview.net/WebLog

O Neal Gafter (programador do javac) respondeu ao primeiro post do Bruce Eckel:

louds

“AllMighty”:

Essa eu não entendi. O objetivo do generics é melhorar a checagem estática (em tempo de compilação) dos tipos. O que muita gente acha ruim (inclusive eu) é que é somente esse o objetivo.

Tipagem estática != tipagem forte.

Em java se eu fizer:

String string = ....;

Não existe forma de subverter isso em tempo de compilação ou execução e guardar algum valor nessa variavel que não seja do tipo String.

Agora em:

Collection<String> collection = ....;

Não existem garantias que durante a execução somente vão existir objetos do tipo String nessa coleção.

O código abaixo pode lançar um ClassCastException:

List<String> list = ...;
....
String str = list.get(0);

Ou seja, java vai ganhar uma forma de tipagem fraca com Generics.

_fs

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)

que isso cara … que isso :expressionless:

A

E se eu fizer isso?

String string = "umastring";
...
Object o = string;
....
String string2_a_missao = (String)o;

Mas esse código aqui também não pode lançar um ClassCastException?:

List listaNaoGenerica = ...;
....
String str = (String)list.get();

Eu acho que em runtime não se está fazendo nem mais nem menos checagem do que antes. Em tempo de compilação se está, sim, fazendo mais checagem.
Por favor me corrijam se eu estiver errado.

louds

Allmighty, acho que você não entendeu a idéia que eu quis passar.

Dada a seguinte classe:

public class StringValueHolder {
  String value;
  public void setValue(String value) { this.value = value; }
  public String getValue() { return value; }
}

A linguagem me garante que a todo momento o atributo value vai armazenar uma String e getValue() vai sempre retornar algo do tipo String. Ou seja, vai ser sempre String.

Agora em

public class ValueHolder<T> {
  T value;
  public void setValue(T value) { this.value = value; }
  public T getValue() { return value; }
}

Eu posso fazer o seguinte:

ValueHolder<String> var = new ValeHolder();
var.setValue("oi");
String value = var.getValue();

ValueHolder<Integer> ops = (ValueHolder)var;
ops.setValue(666);

//...............................................................................
String value2 = var.getValue(); // !!!! ClassCastException

Viu como Generic não tem tipagem forte? Ou seja, é possivel subverter o sistema de tipos de Generic e fazer esse tipo de besteira.

saoj

“louds”:
Não, com Generics os castings somente apenas do código.
O bytecode gerado é quase igual ao gerado hoje para um código sem generics.

Onde vc escreveu Não eu acho que vc queria dizer Sim, pois isso foi exatamente o que eu falei no início. Para o bytecode, generics não existe e o casting acontece de qualquer jeito, ou seja, em termos de performance não há economia de casting.

A

Eu não sabia que o javac deixava fazer cast de um tipo parametrizado para ele mesmo com outro parâmetro. Fui testar e ele dá um Warning na linha do cast, mas compila.

Para fazer gerar esse tipo de problema você usou um cast no código. E casts sempre permitem que se subverta a checagem de tipo na compilação. Um exemplo mais trivial:

String a = "oi";
    Object o = (Object)a;
    Integer i = (Integer)o; // ClassCastException!
    ...
    System.out.println("O dobro? " + (2.0 * i.doubleValue()));

Eu ainda não vi como o generics torna o java uma linguagem de tipagem fraca…

[size=“9”]OBS: Editei mensagem pq tinha apontado a linha errada p a excecao.[/size]

louds

A vai precisamente tornar a linguagem de tipagem mais fraca.

Mas vai dar tal impressão, visto que voce pode subverter o sistema de tipos agora.

Qual a relação com o teu exemplo usando castings com oque estamos discutindo?

A

Isso pode parecer meio óbivo, e é mesmo: quando se usa Cast’s explícitos sempre se incorre no risco de uma ClassCastException. Especialmente considerando que Java usa late-binding nas chamadas de métodos.

Na minha opinião o Generics simplesmente ajuda a encontrar mais cedo alguns erros desse tipo. Mas acho que a ajuda não compensa o aumento de complexidade na linguagem. Se fosse uma implementação mais completa (como parece que é a do .net) talvez a balança pendesse para o outro lado.

Voltando ao meu exemplo, eu só quis mostrar que usar cast’s sempre é arriscado, mesmo sem generics. E quanto a subverter o sistema de tipos, eu não pensei muito sobre isso, mas acho improvável encontrar esse tipo de erro em sistemas reais. Ainda mais considerando que o compilador dá um warning para esse tipo de coisa.

Enfim, resumindo, eu também não sou muito fã do Generics.

louds

Eu penso exatamente o contrario.
Veja que ninguêm vai converter todo um sistema e as bilbiotecas que usa para usarem generics da noite pro dia.
Acho mais coerente imaginar que vai se levar algum tempo para sair do mundo hibrido, com metade do código feito pra generics e a outra metade não.

O intuito do meu exemplo era mostrar que generics permite fazer o erasure dos tipos dos parâmetros, coisa que é impossivel com o tipo dos demais artefatos da linguagem.

Criado 27 de setembro de 2004
Ultima resposta 28 de set. de 2004
Respostas 30
Participantes 10