Sobrecarga de Operadores

53 respostas
A

Olá Pessoal.

Por que Java não tem sobrecarga de operadores.

Andei aprendendo Python recentemente e me parece um recurso bem util, existe alguma questão de design que faz com que eles não implementem ?

O que voces acham, tipo

ArrayList l1 = new ArrayList(3);
l1[0] = "A"
l2[1] = "B"
l3[2] = "C"

ou com mapas

Map m = new HashMap();
m["Nome"] = "Joao";

com um StringBuilder

StringBuilder b = new StringBuilder();
b += " Olá Mundo ";
b += new char[]{'A','B','C'};
b += true;
b += 123;

no caso substituindo os append.

ou então nas suas proprias classes

public class Caixa
{
     private ArrayList items = new ArrayList();

     public void __setitem__(index, valor){
          items[ index ] = valor;
     }

     public void __getitem__(index){
          return items[ index ] ;
     }

}

Enfim não daria mais produtividade ?

Falow a todos

53 Respostas

cv1

Sobrecarga de operadores eh util pra um numero tao pequeno (porem extremamente frequente) de usos, que eu nao sei se vale a pena ser feature da linguagem.

Por outro lado, dah uma olhada no que o why_ fez no hpricot :wink:

maquiavelbona

Tem gente que acha que sim, tem gente que acha que não. Já foi discutido isso várias vezes.

Se quiser, vote aqui para ter operator overloading.

http://forum.java.sun.com/thread.jspa?threadID=624342&messageID=3550166

Até!

saoj

Seria muito bom para contornar o sofrível suporte a aritmética com datas do Java…

Pior que isso só regular expressions com o seu match tentando dar um match na string inteira e não apenas em qualquer parte dela…

S

O problema é: o que um código desses faz?

Carro c1 = new Carro(); Carro c2 = new Carro(); Carro c3 = c1 + c2
Soma os anos de fabricação, a capacidade dos tanques, a quilometragem rodada ou não tem nada a ver?
Flexibilidade e legibilidade andam em sentidos opostos. Não sei até que ponto isso vale a pena.

cv1

Chama o metodo public Carro +(Carro) da classe Carro, ueh. O que esse metodo faz depende da implementacao. :wink:

Andre_Breves

Sinceramente não concordo com o argumento de que overload de operadores podem deixar o código mais complicado ou afetaria a legibilidade. Tudo depende do programador, assim como ocorre com o nome de método. Eu poderia muito bem fazer um método chamado add() que multiplicasse ao invés de somar.
A possibilidade de operador sobrecarregado não seguir a semântica padrão não é maior que com os nomes dos métodos, mas em compensação se teria uma grande vantagem de simplificar a sintaxe em muitas construções.

S

Chama o metodo public Carro +(Carro) da classe Carro, ueh. O que esse metodo faz depende da implementacao. ;)

Mas é isso que considero o problema: você precisa ver a implementação pra saber o que ele faz.

Tá, aí você poderia escolher um nome ruim. Mas, no caso do operador, não há nome algum. (Meu exemplo é meio tosco, é verdade).

A

Ou então ver o Javadoc, como em qualquer outro método. :wink:

public class Caixa
{

     /**
      * @param caixa a caixa que será adicionada.
      * @return uma nova caixa cujos itens são as somas dos itens desta         
      * caixa com a caixa de parametro. 
      */
     public Caixa +(Caixa caixa){
          Caixa caixa = new Caixa();
          caixa.setItens( this.itens.clone() + caixa.itens.clone() );
          return caixa;
     }
}

No caso o operador seria uma mera abreviação do metodo, para dar mais legibilidade, mais nada impediria voce de documenta-lo.

maquiavelbona

E se eu tivesse 2 classes com o “+” sobrecarregado com comportamentos diferentes? E se tivesse 20? E 200? Iria ficar lendo o javadoc de todas para saber o que o “+” faz em cada uma?

O Java querendo adotar um padrão e vocês querendo fugir de um comportamento comum.

Até!

urubatan

maquiavelbona:
E se eu tivesse 2 classes com o “+” sobrecarregado com comportamentos diferentes? E se tivesse 20? E 200? Iria ficar lendo o javadoc de todas para saber o que o “+” faz em cada uma?

exatamente a mesma coisa que tu tem que fazer com o metodo add de todas estas 20 ou 200 classes

A

maquiavelbona:
E se eu tivesse 2 classes com o “+” sobrecarregado com comportamentos diferentes? E se tivesse 20? E 200? Iria ficar lendo o javadoc de todas para saber o que o “+” faz em cada uma?

O Java querendo adotar um padrão e vocês querendo fugir de um comportamento comum.

Até!

Não entendi, no caso assim como num metodo o operador do objeto à esquerda ia ser aplicado.

public class Caixa
{
   public Caixa +(Caixa c){
          Caixa caixa = new Caixa();
          caixa.setItens( c.getItens().clone(), this.getItens().clone() );
          return caixa;
   }
}

public class SuperCaixa extends Caixa
{
   public SuperCaixa +(SuperCaixa c){
          SuperCaixa caixa = new Caixa();
          caixa.setItens( c.getItens().clone(), this.getItens().clone() );
          return caixa;
   }
}

Exemplo de uso:

Caixa c1 = new Caixa();
SuperCaixa c2 = new SuperCaixa();

Permitido pois c2 é um tipo de caixa:

Caixa c3 = c1 + c2;

Daria erro pois nem toda caixa é uma SuperCaixa

SuperCaixa c4 = c2 + c1;
maquiavelbona

Colocar o nome dum método de add sendo que vai ter N métodos parônimos é deveras estúpido. Se você soma um carro com um carro, e um parafuso com um parafuso, os métodos, em tese, deveriam ser nomeados singularmente, pois os comportamentos são singulares. Senão, de nada adianta essa verborréia na convenção se você não faz uso dela. Se vais somar carros, supôe-se que seja algo do tipo addCar, se vai somar parafusos, addScrew ( ou suas variantes addAnotherScrew, addOneMoreScrew, addLotsOfScrews(List listScrews)), assim por diante.

Até!

Obs.: Desculpem o estúpido, não achei palavra melhor. Não se sintam ofendidos com meu vocabulário diminuto.

maquiavelbona

Aliás, somar carro com carro, para mim, é coisa de recuperadora de veículos. Faz sentido somar produtos a uma cesta. Se ambos fossem sobrecarregados com “+”, o comportamento do primeiro seria juntar dois carros, do segundo aglomerar produtos dentro de um cesta. Viu que complicação sendo que existe uma convenção de símbolos?

Até!

A

maquiavelbona:
Aliás, somar carro com carro, para mim, é coisa de recuperadora de veículos. Faz sentido somar produtos a uma cesta. Se ambos fossem sobrecarregados com “+”, o comportamento do primeiro seria juntar dois carros, do segundo aglomerar produtos dentro de um cesta. Viu que complicação sendo que existe uma convenção de símbolos?

Até!

Mais isso de fazer sentido varia de acordo com a sua regra de negócios, não tem nada a ver com a linguagem.

Eu poderia ter um produto que ao ser somado com outro seria um produto composto. :wink:

tipo minha regra de negócios diria que posso comprar tanto um Saco de Arroz quanto juntar diversos produtos e virar um só

Produto cestaBasica = new Produto();

cestaBasica += new Produto("Arroz");
cestaBasica += new Produto("Macarrao");
cestaBasica += new Produto("Feijão");
cestaBasica += new Produto("Tamarindo");
cestaBasica += new Produto("Café");
cestaBasica += new Produto("Caviar");
//... etc.
nbluis

Mas tudo isso para trocar um “add” por um “+”?
Não acho legal não.

Tem sempre gente reclamando por ai que java suporta coisas demais, por isso da complexidade.

Tem tanta gente estusiasmada com o RoR exatamente pela simplicidade do mesmo, agora por que vamos encher o java de “jeringonças”(não sei como se escreve isso), simplesmente para dar “maaaais uma” possibilidade de dinamizar o código porém sem ganho nenhum?

maquiavelbona

Então, vocês querem obscurecer essas formas díspares de trabalho com operadores comuns. Recai no que eu comentei sobre os métodos add parônimos. Dentro de um sistema, que pode virar um monstro no curto ou longo prazo, deixar livre essa escolha pode ( e em geral vai ) se tornar prejudicial a interpretação. Numa parte do código, o “+” mescla dois produtos, em outra “+” agrupa emails de um cliente, em outra incrementa o contador de visitas, em outra sobrepõe o endereço de entrega etc.

Com a verbosidade levantada para deixar o código mais legível, frente as reclamações das linguagens que usam nomes obscuros( ou alguém logo de primeira, só de bater o olho, já sabe o que faz array_uintersect_uassoc ) , sobrecarregar símbolos para supostamente deixar mais legível, tende a ficar paradoxal.

Até!

sergiotaborda

AndrewAguiar:
Olá Pessoal.

Por que Java não tem sobrecarga de operadores.

A razão para isso é simplicidade e manutenção da linguagem.
Quando vc tem sobrecarga de operadores, na realidade vc pode implementar sublinguagens. Imagine que cada API de terceiros, por ai, criáva seus proprios operadores. Ia ser uma dor de cabeça…
Associação de operadores como é usado no Groovy parece mais interessante. Por exemplo, o sinal + pode ser usado por qq classe que implemente plus() e o sinal * por multiply() e variável[“string”]=a por put(“string”,a) e assim vai. Agora definir novos simbolos (como se faz no C) parece meio caminho andado para complicar demais as coisas.

cassio

Acho que simplesmente permitir a sobrecarga do operador ‘+’ no Java não iria mudar tanta coisa assim, como já foi falado, o método add() aparece atualmente em trocentas classes, dá no mesmo. A questão é que sobrecarga de operadores vai muito além do operador ‘+’ (digo isso porque quase toda a discussão neste tópico ficou focada neste operador). Se a feature de sobrecarga de operadores fosse aprovada no Java num molde semelhante ao que temos em C++, poderiamos sobrecarregar praticamente qualquer operador. Isso inclui:
++

/
*
[]

!=
&lt
&gt

e por ai vai.

Perceberam o nível de complexidade disso? Se deixar, vira uma zona fácinho, fácinho.
Eu não quero ficar comendo documentação, quero escrever código. Do mesmo modo que utilizar add() é ambiguo, utilizar sobrecarga de operador também é. Dá na mesma procurar na documentação de todas as classes que implementam uma interface que possui o método add() ou nas subclasses de uma classe que sobrecarrega o operador ‘+’.
enfim, uma bagunça…
Por outro lado, para tentar acabar com ambiguidade no nome de métodos, temos que tornar o Java cada vez mais verboso, com nomes de métodos que definam exatamente o comportamento esperado, para todas as classes. Eu acho que já escrevo demais para programar em Java…
Sinceramente não vejo muita solução para isso não. Vai de estilo de programar. Java não tem sobrecarga, ponto final. Quer sobrecarga, vai programar em C++. Mas também não reclama que Java é verboso… Temos que conviver com isso.

A

nbluis:
Mas tudo isso para trocar um “add” por um “+”?
Não acho legal não.

Tem sempre gente reclamando por ai que java suporta coisas demais, por isso da complexidade.

Tem tanta gente estusiasmada com o RoR exatamente pela simplicidade do mesmo, agora por que vamos encher o java de “jeringonças”(não sei como se escreve isso), simplesmente para dar “maaaais uma” possibilidade de dinamizar o código porém sem ganho nenhum?

E por que fizeram o for-enhanced ? :smiley:

Teoricamente tudo que voce faz no for-enhaced voce ja conseguia fazer antes com o for normal.

para dar agilidade.

E pelo que sei Ruby apesar da simplicidade tem sobrecarga de operadores.

também concordo que definir simbolos novos é meio suicida, mais poderia ser assim voce pode sobreescrever somente os operadores já existentes operadores…

nbluis

Concordo sobre o for enhanced…
E não citei ruby quanto a ter ou não sobrecarga.

Meu exemplo foi apenas para citar que esse é mais um dos que um cara acostumado com outra linguagem mais vai olhar um código java e vai dizer “WTF”.
Ao invés de agilidade, traríamos mais complexidade sem agregar em nada.

Qual a diferença na agilidade você consegue enxergar nessas duas representações?

public add(T a){
  /*codigo*/
}
public +(T a){
  /*codigo*/
}
S

Eu acho a diferença entre uma chamada de método e o uso de operador bem pequena, se comparada à entre for-enhanced e usar iterator (embora eles pudessem ter criado um “foreach”).

Não consigo ver muita vantagem no uso de sobrecarga de operadores. Talvez se conhecesse melhor, veria.

maquiavelbona
nbluis:
Concordo sobre o for enhanced....
Eu não. O enhanced for é só uma maneira de não tornar aparente o uso do Iterator, não uma sobrecarga de lógica. Quem quiser comparar, compile e rode depois com javap -verbose:
import java.util.ArrayList;
import java.util.Iterator;
public class TesteFor {
	public static void main(String[] args) {
		ArrayList<String> listaTeste = new ArrayList<String>();
		listaTeste.add("String 1");
		listaTeste.add("String 2");
		listaTeste.add("String 3");
		System.out.println("Maneira 1 de fazer o for");
		Iterator<String> it = listaTeste.iterator();
		do{
			String nome = (String) it.next();
			System.out.println(nome);
		}while(it.hasNext());
		
		System.out.println("Maneira 2 de fazer o for");
		for (String string : listaTeste) {
			System.out.println(string);
		}
	}
}

Coincidentemente, os dois loops em bytecode são muito parecidos. O mesmo não aconteceria se fosse trabalhado sobrecarga do operadores como no C++.

Continuo convicto que a verborragia é uma convenção muito boa. espalhar métodos parônimos por todo lado pode ser extremamente prejudicial.

Até!

A

nbluis:
Concordo sobre o for enhanced…
E não citei ruby quanto a ter ou não sobrecarga.

Meu exemplo foi apenas para citar que esse é mais um dos que um cara acostumado com outra linguagem mais vai olhar um código java e vai dizer “WTF”.
Ao invés de agilidade, traríamos mais complexidade sem agregar em nada.

Qual a diferença na agilidade você consegue enxergar nessas duas representações?

public add(T a){
  /*codigo*/
}
public +(T a){
  /*codigo*/
}

Exemplo:

Sem Operador:

StringBuilder b = new StringBuilder();
b.append( "A" );
b.append( "B" );
b.append( "C" );
b.append( "D" );
b.append( "E" );
b.append( "F" );
b.append( "G" );
b.append( "E" );
b.append( "H" );
b.append( "I" );
b.append( "J" );
b.append( "L" );
b.append( "M" );
b.append( "N" );

Com operadores:

StringBuilder b = new StringBuilder();
b = b + "A" + "B" + "C" + "D" + "E" + "F" + "G" + "E" + "H" + "I" + "J" + "L" + "M" + "N";

Bem mais simples e limpo :smiley:

No caso os operadores resolvem da esquerda para a direita e a implementacao poderia ser.

public StringBuilder +(Object o){
       return this.append( o );
}
maquiavelbona

Sem tentar forçar a barra:

StringBuilder b = new StringBuilder(); b.append("A").append("B").append("C").append("D").append("E").append("F") .append("G").append("E").append("H").append("I").append("J").append("L") .append("M").append("N"); System.out.println(b.toString());

Até!

A

Sem tentar forçar a barra:

StringBuilder b = new StringBuilder(); b.append("A").append("B").append("C").append("D").append("E").append("F") .append("G").append("E").append("H").append("I").append("J").append("L") .append("M").append("N"); System.out.println(b.toString());

Até!

Mais ai voce esta escrevendo 8 caracteres a mais para implementar:
b.append(“A”)

e o código fica bem mais dificil de entender.

no outro não, voce só de bater o olho ja sabe o que esta havendo.

Eh claro que também não adianta escrever pouco e depois se ferrar para entender o código, mais no caso com o operador fica até mais claro a intenção do código.

maquiavelbona

Vais ter que criar outro método para fazer o que o append já faz, além de ter que transformar o “+” em um método que já existe (será que não irá montá-lo como append em bytecode?).
Conheço bons programadores que reclamam do C++ por permitir isso, pois eles odeiam os antigos mantenedores do código que eles estão trabalhando agora.

Mas “+” o mais poderia significar add(), append(), put(), offer(), doSomethingThatIDontKnowWhatItDoes() e tantos outros métodos diferentes que eu acho que a vantagem que ele talvez desse em criação seria sobrepujado pela complicação em manutenção.

Até!

A

Não só delegar para o original, assim se mudar a implementação os dois mudam, no caso de classes basicas eles simplesmente dariam os operadores como uma maneira mais simples de fazer o mesmo trabalho do metodo. Não tiraria a compatibilidade com nada antigo e ainda quando o programador quisesse mudar o metodo append por exemplo ele só mudaria ele, ja que o operador chama este…

public StringBuilder +(Object o){
      return append(o);
}

Que complicação haveria em dar manutencao nestes metodos ?

maquiavelbona
ProcessHandler p = new ProcessHandler();
p = p + requisicao;

Podes me falar se o “+” é add(), offer(), publish(), merge(), concat(), kill() ou outro método só de bater o olho? O método é explicativo por si só?

Até!

Obs.: Mudei o nome da classe para não falar que minha classe nao diz nada.

maquiavelbona

AndrewAguiar:

Que complicação haveria em dar manutencao nestes metodos ?

Pense que você tem 200 classes que o “+”, “-”, “/” “>>” fazem coisas diferentes? Como saber qual será o comportamento sendo que “>>” pode simplesmente dar um System.out.println() ou pode fazer uma operação maluca? Isso em não garante legibilidade, garante que você pode se confundir com o tempo.

Até!

faq

IMHO:
Faz sentido a implementação do “+” ser kill, concat ou whatever? Se sim, quem está fuçando no código vai saber.
A criação de um novo simbolo realmente é uma coisa estranha (mas que, dependendo de como o seu sistema/ambiente/plataforma oferece acesso/suporte, pode ser legal) , a redefinicão de uma mensagem é uma coisa normal.
Em java, sobreescrever “+” faz 0 de diferença. Eu quero reescrever o new, o class, o …

pcalcado

Sobrecarga de operadores é um artifício muito útil, especialmente para construir Human Interfaces e DSLs internas, mas não é essencial.

O ‘mistério’ que poderia fazer com que olhar o JavaDoc para cada classe e ver o que o + (ou-, ou/,ou []) faz deriva do fato de que você está assumindo que + é um operador quando em uma linguagem decente que tenha sobrecarga de operadores ela é apenas um apelido para um método e assim como todos os métodos você precisa saber o que esperar.

maquiavelbona

faq:
IMHO:
Faz sentido a implementação do “+” ser kill, concat ou whatever? Se sim, quem está fuçando no código vai saber.

Não necessariamente. O cara pode estar se adaptando ao código e encontrar isso. O nome auto-explicativo dos métodos vai para onde?

faq:

A criação de um novo simbolo realmente é uma coisa estranha (mas que, dependendo de como o seu sistema/ambiente/plataforma oferece acesso/suporte, pode ser legal) , a redefinicão de uma mensagem é uma coisa normal.
Em java, sobreescrever “+” faz 0 de diferença. Eu quero reescrever o new, o class, o …

Faz diferença sim, como já mostrei. E depois ainda queres trazer os define para o Java? :shock:

Até!

A

maquiavelbona:
AndrewAguiar:

Que complicação haveria em dar manutencao nestes metodos ?

Pense que você tem 200 classes que o “+”, “-”, “/” “>>” fazem coisas diferentes? Como saber qual será o comportamento sendo que “>>” pode simplesmente dar um System.out.println() ou pode fazer uma operação maluca? Isso em não garante legibilidade, garante que você pode se confundir com o tempo.

Até!

Voce olha no javadoc, qualquer API que voce pegar para usar voce vai ser obrigado a olhar a documentação. se voce ve o seguinte metodo numa api que voce pegou de um terceiro

Messenger msg = new Messenger();
msg.enviar("Olá");

blz voce ( Presume ) pelo nome que este metodo envie a mensagem.
porem voce ainda não sabe que exceções ele lança, não sabe se há uma restrição no seu uso, não sabe no que impacta no Objeto, não sabe se esta depreciado ou não etc.

Simplesmente olhar o nome do método não te diz muita coisa.

Thread thread = new Thread( new Runnable(){
   		public void run() {
   			System.out.println("Foi");
   		};
   	});
   	thread.start();

Imagine que voce nunca usou a Thread, voce conseguiria só vendo o nome do metodo start dizer que ele lança um IllegalThreadStateException se voce tentar startar ela denovo ?

O fato do nome do metodo ser verboso ajuda, mais não te livra de ler sua documentação.

faq

Ok. Vamos levar em consideração que quem escreveu o código tem bom senso. Você costuma ver muitos “adds” fazendo - subtrações - ? Eu espero que o “+” faça algo como somar.

Maquiavel sobre criação de novos simbolos:

Define do c? Eu não quero trazer nada pro java. Só acho que criar novos simbolos pode ser legal.
Acho que no fim cada um continua com uma opinião. Uns achando que a linguagem deve ser o que deve ser (sem reescritas) e outros achando que reescrever coisas é legal. Eu fico com o segundo grupo, pois até onde sei/entendo é esse tipo de coisa que permite expressividade e simplicidade.

pcalcado

http://blog.fragmental.com.br/2007/07/27/construindo-expressividade-com-linguagens-elegantes/

maquiavelbona

Eu achei que simplificaste demais a acepção do uso da Sobrecarga de Operadores. O que mais critico nela ( como na tupla também, apesar de ser assunto para outro tópico ) é o péssimo uso e a falta de senso na aplicação da mesma. E o pior que isso não afeta somente as linguagens de programação.
Estava conversando com um doutorando na área de literatura, e ele me dizia que no meio acadêmico estuda-se a penetração e crescimento das sinonímias e paronímias vulgares dentro de línguas consagradas ( português é um exemplo ), e como isso afetava a norma culta, levando tanto ao emprego errôneo de várias palavras, quanto ao desuso e desconhecimento de outras. Na frase “Percebo R$5000,00 todo mês”, quantas pessoas pensariam que o cara estaria falando do seu salário? Mas “Tomaram o cara” todo mundo entende. É a mesma cosia da vulgarização do método add(), pode significar várias coisas e nenhuma ao mesmo tempo.
Outro termo que ele estávamos discutindo é o uso dos verbos reduzidos de infinitivo, que o uso correto e lógico dentro de uma frase, pode torná-la mais compreensível ao nosso cotidiano, mas que quase nunca é empregado corretamente ( não lembra a sobrecarga do “+” ? ).

Como na língua portuguesa, poderíamos ter a disposição vários artifícios como esses, o problema seria fazê-los compreensíveis a todos e que a implementação dos mesmos não ficasse tão vulgar quanto o uso do define do C.

Até!

Andre_Breves

As Línguas de maneira geral, como o Português e Java num menor grau, têm que ser dinâmicas e se adaptarem aos usos e necessidades, se quiserem sobreviver. Quem realmente dita as regras é quem usa, não quem especifica (por isso as reformas da norma culta e o JCP :slight_smile: ). As novas regras de qualquer língua têm sua origem no uso vulgar.

Quanto à semântica de um operador sobrecarregado, não consigo ver como isso seria diferente de um nome de método. O programador dá o significado que quiser em ambos os casos.

maquiavelbona

Na língua portuguesa, a "reforma" vulgar não vem da "lei do menor esforço" e sim da "lei estudar-para-que?". No Java, algumas (eu disse algumas) mudanças seriam bem aceitas, mas outras seriam simplesmente um paleativo para pessoas que sabem que estão usando errado e querem um jeito de não ser tão feio o que estão fazendo ou não saber realmente como fazer e para infelicidade do destino, descobre-se que ele pode refazer os operadores ( ao melhor jeito do define ) e transformá-los em mutantes comedores de código legível. No começo do código, o "&lt&lt" vai estar jogando um valor num objeto e no fim vai estar juntando um valor randômico com o número do MAC adress e escrevendo isso num socket.

Não é porque você pode ( e consegue ) escrever código legível com isso, que os estagiários que mantiveram as URAs donde trabalhas vão ter o mesmo esmero.

Até!

Luca

Olá

Durante muitos anos estive convencido de que uma das melhores coisas do Java era não ter sobrecarga de operadores que foi uma das coisas que mais sofri quando aprendi C++ há uns 15 anos atrás.

Mas depois que andei estudando erlang, Scala e até mesmo Ruby, que são linguagen que tem coisas bem mais esquisitas do que isto, penso que Java poderia ter isto sim.

Como disse o CV, não é coisa que todo mundo iria usar a toda hora. Mas nos poucos momentos em que pode ser útil seria muito vantajoso. Um exemplo clássico são as aplicações que precisam de números complexos. Outro momento em que faz falta é quando a gente usa BigDecimal ou quer fazer operações aritméticas com vetores.

Hoje em dia acho que o Java precisa de muitas coisas a mais na linguagem para continuar útil nos próximos anos. Muitas destas coisas talvez devam ser oriundas das linguagens funcionais e podem complicar a VM mas sobrecarga de operadores deve ser coisa simples porque de certa forma já existe nas Strings.

Quem quiser brincar pode experimentar o JFront (A preprocessor to add C++ style operator overloading to Java.):
http://www.gginc.biz/jfront/index.html

[]s
Luca

maquiavelbona

Luca:
Olá

Durante muitos anos estive convencido de que uma das melhores coisas do Java era não ter sobrecarga de operadores que foi uma das coisas que mais sofri quando aprendi C++ há uns 15 anos atrás.

Mas depois que andei estudando erlang, Scala e até mesmo Ruby, que são linguagen que tem coisas bem mais esquisitas do que isto, penso que Java poderia ter isto sim.

Como disse o CV, não é coisa que todo mundo iria usar a toda hora. Mas nos poucos momentos em que pode ser útil seria muito vantajoso. Um exemplo clássico são as aplicações que precisam de números complexos. Outro momento em que faz falta é quando a gente usa BigDecimal ou quer fazer operações aritméticas com vetores.


Não acho ruim a funcionalidade em si, e sim o que pode ser gerado com issso. Poderia facilitar N códigos que trabalho e de muitas outras pessoas.

Ter em algum lugar é diferente de disponibilizar para uso indiscriminado. O seu colega, leitor fanático do JavaRanch, vai ver que tem isso na linguagem e vai sair colocando essa joça em todos os lugares possíveis e imagináveis e transformar um simples “shift-right” em um disparador de processos e consultas intermináveis que só pararia depois de um ack/0 (sim, dividir por 0, claro que ele mudou a “/” também).

Luca:
Quem quiser brincar pode experimentar o JFront (A preprocessor to add C++ style operator overloading to Java.):
http://www.gginc.biz/jfront/index.html

[]s
Luca


Depois vou dar uma olhada, conhecer esse tipo de ferramenta faz bem a saúde.

O exemplo que eu coloquei é real, só mude a linguagem de Java para C++ e mude o JavaRanch pelo cprogramming.com . E o pior que ele tinha evangelizado o estagiário a usar isso. :frowning:

Até!

pcalcado

Eu achei que simplificaste demais a acepção do uso da Sobrecarga de Operadores. O que mais critico nela ( como na tupla também, apesar de ser assunto para outro tópico ) é o péssimo uso e a falta de senso na aplicação da mesma. E o pior que isso não afeta somente as linguagens de programação

Como na língua portuguesa, poderíamos ter a disposição vários artifícios como esses, o problema seria fazê-los compreensíveis a todos e que a implementação dos mesmos não ficasse tão vulgar quanto o uso do define do C.

Pode dar algum exemplo ou argumento concreto do porque eu fui simplista?

Eu acho que você perdeu exatamente o ponto principal do meu post e de todos os recursos citados: meta-programação. Sem os mecanismos que você critica (não apenas esses) não existe meta-programação, se uma linguagem não é redefinida usando a si mesma seu modelo de MOP é fraco. Se é para programar ‘normalmelte’, quando os construtos da linguagem te bastam, concordo com você mas quando se quer ir além, como quando usamos Model Driven Design e DSLs, não.

A

E qual a diferença entre ele fazer isso sobrescrevendo o operador e fazer com um método. Isso é um problema do programador não da linguagem.

Não digo permitir voce sobreescrever em classes bases pois isso sim seria uma zona, mais nas classes que voce criar seria bom.

ViniGodoy

Muitos livros de C++ recomendam sobrecarga de operadores apenas em classes que representam tipos matemáticos.
Veja por exemplo como seria bom sobrecarga em classes como BigNumber, BidDecimal, Vector (vetor matemático), Angle, etc.

Nas demais classes, o uso é um tanto questionável. Já vi abominações em C++.

O fato é que, infelizmente, não se pode contar que todos os programadores de uma equipe tenham bom senso e nem que todos sejam experientes. Então, via de regra, gosto da idéia do Java de restringir coisas que podem gerar um código pouquíssimo legível.

cv1

Não acho ruim a funcionalidade em si, e sim o que pode ser gerado com issso. Poderia facilitar N códigos que trabalho e de muitas outras pessoas.

Entao pronto, ueh. Se vc acha que Java nao dah corda suficiente pra imbecis se enforcarem, ou vc trabalha em algum lugar excepcional ou nao tem la tana experiencia. Adicionar sobrecarga de operadores, heranca multipla, closures ou qualquer outra coisa que seja “enabling” nao eh lah uma diferenca tao grande, a nao ser pela mudanca de mentalidade da linguagem em geral.

Leia http://www.martinfowler.com/bliki/SoftwareDevelopmentAttitude.html :wink:

rodrigo_gomes

Exato! Isso já fez muito falta (no uso de BigDecimal).
No meu caso, o sistema permite que usuários - super acostumados com excel - definam algumas formulas que o sistema precisa calcular.
Imagine o cara (que não é de TI) escrevendo taxaX.add(valorY). Não é natural.
Nesse caso fui salvo pelo groovy, mas se não fosse permitido usa-lo eu teria problemas.

Fora o uso matematico, acho que como o ViniGodoy disse, o uso é um tanto questionável.

[]´s

L

O que eu estou achando estranho nessa conversa é achar que sobrecarga de operador só existe para operações aritméticas. Não é. Eu não sei quanto a vocês, mas eu aprendi C++ depois que eu aprendi Java, quase no mesmo período do Ruby on Rails. E eu pude perceber o seguinte: em C++ tem sobrecarga de operador pra tudo!

Por exemplo: o operador() que faz com que um objeto aja como uma função, o operador-> que “derreferencia” um objeto, mesmo que este esteja alocado no stack, e o operador qualquer_coisa(), que transforma um objeto em outro, sendo possível criar um código desse jeito abaixo, sem nenhum problema de compilação:

Banana banana;
Melancia melancia;
melancia = banana;

O C++ é um caso extremo, é uma linguagem que tem a vantagem de permitir você fazer tudo, e que tem a desvantagem de permitir você fazer tudo.
Porém a sobrecarga é útil associado a outros recursos da linguagem. Em C++, poderíamos usar templates em um método cujo único requisito é que tipo de entrada tivesse o operador +; em Ruby, com a tipagem dinâmica, receberiamos qualquer coisa de um método, também cujo requisito fosse o operador +.
Além disso, em C++, a sobrecarga é o único meio de se adicionar recursos depois que a classe já tivesse sido “fechada”. Já em Ruby, não existe classe fechada.

Em Java, não tem nada parecido com tipagem tipagem dinânica, nada parecido com templates (tá, tem gente que acha que Generics é Template, eu digo que não, pois Generics é muito restritivo e não passa de “syntactic-sugar”), nada para extender um objeto. E ainda por cima, criou-se uma divisão artificial entre tipos primitivos e objetos, que não existe paralelo nem em C++, nem em Ruby.

Acredito que uma linguagem de programação como Java pode sim ter sobrecarga de operadores, desde que fose adicionado outros recursos como alguma refatoração na especificação do Generics (coisas básicas como permitir T var = new T() dentro uma classe que receba um generic), algum recurso de programação orientada a aspectos e a uniformização entre tipos primitivos e objetos.

sergiotaborda

Na boa verdade aritmética com datas não existe. (Qual seria o resultado de 1/1/2000 + 1/1/2007 ?)
Existe aritmética de intervalos de tempo, e mesmo assim não existe 1 aritmética existem várias.
Por exemplo: 1/1/2007 - 1/1/2000 poderia ser 7 anos , poderia ser 365*7 anos , poderia ser o numero exato de dias transcorridos entre as datas (!) poderia ser o numero de dias uteis entre as duas datas, poderia ser o numero de meses entre as datas, poderia ser o numero de seculos entre as duas datas, etc…

Data é conceito de depende fortemente do conceito de calendário. E calendário é uma subdivisão do tempo de forma que depende de fatores culturais.

Os operadores + e x não estão definidos e o operador - que ainda faz algum sentido, tem N formas de ser intrepretado. E qualquer uma delas resulta em um numero e não em uma data.

Trabalhar com datas é muito mais difícil do que parece. E parece-me que não seria tão boa ideia ter suporte a estas aritméticas usando operadores.

sergiotaborda

rodrigo_gomes:
Luca:

Como disse o CV, não é coisa que todo mundo iria usar a toda hora. Mas nos poucos momentos em que pode ser útil seria muito vantajoso. Um exemplo clássico são as aplicações que precisam de números complexos. Outro momento em que faz falta é quando a gente usa BigDecimal ou quer fazer operações aritméticas com vetores.

Exato! Isso já fez muito falta (no uso de BigDecimal).

Estou vendo muitos de vc defenderem este ponto.
Mas lembrem-se do porquê de BigDecimal não ser um tipo primitivo e do porque de vc poder usar MathContext e do porquê da divisão ter um modo de arredondamento. Sendo assim o que seria a / b ?
Os operadores poderiam favorecer os casos triviais ( que o groovy resolve) mas não os casos especiais, e ai , teria que entrar o uso dos métodos comuns. Ora, se vai usar os métodos comuns, por consistência e simplicidade use esses metodos sempre e não complice a vida tendo que inferir o que significa a/b

O mesmo poderia ser pensado para tipos como Money. Parece razoável que a + b seja possivel com dinheiro, mas na realidade não é. Se a e b não tem a mesma unidade, não são somáveis. Mas eu poderia querer , mesmo assim ,somar. Usando o padrão MoneyBag. Como definir qual eu quero usar ? Com métodos é simples :
a.plus(b) e a.add(b) , com operadores teria que inventar dois operadores diferentes. a +_ b e a _+ b ? :shock:

Se existir a possibilidade de construir esses operadores, concerteza alguem os vai definir. Mas alguem entende o que eles significam só de olhar ?

A utilidade dos operadores , quaisquer que sejam , é diretamente proporcional à unicidade do seu significado.

a + b para numeros é simples, mas a/ b nem sempre é simples. Para inteiros tem certas regras, paras doubles tem outras, mas ambas são bem definidias ( ou seja, não existem casos desconhecidos)
alguem deu o exemplo do + para substituir append() no StringBuffer/Builder, so que + já é um operador entre CharSequence

StringBuffer a
StringBuffer b

c = a + b , significa  c = new StringBuilder().append( String.valueOf(a)).append( String.valueOf(b) );

e não c = a.append(b). A diferença está no new; c tem que ser um objeto tal que c != a e c != b

caso contrario vira uma zona. a.append(b) não pode retornar um buffer diferente, ele retrorna this exactamente

para não forçar a criação de objetos intermediários ( que é o objetivo de usar buffer/builder)

Usar + é prático, mas todo o mundo sabe que não se deve usar. StringBuffer (StringBuilder) é preferivel.
Isso é suficiente para mostrar como o uso de sobrecarga de operadores é danoso e perigoso, mesmo até aquele que o java já tem.

A

Operador entre CharSequence ? onde ?

pelo que eu saiba voce naum pode fazer isso:

CharSequence b1 = new StringBuilder();
CharSequence b2 = new StringBuilder();

System.out.println( b1 + b2 );

Não… no caso significaria:

StringBuilder a = new StringBuilder("A e");
StringBuilder b = new StringBuilder(" B");
StringBuilder c;

c = a + b

onde o operador + sobrecarregado seria:

public StringBuilder +(CharSequence s) {
        return this.append( s );
    }

sem o new.

sergiotaborda

Operador entre CharSequence ? onde ?

Bom, na verdade é entre qq Object. eu restringi a CharSequence para ter mais significado no contexto
dos operadores, mas ok.

Porquê ? que erro é que dá ?

ViniGodoy

Acho que o maior problema aqui é o seguinte.

Programadores são seres humanos.

E seres humanos pensam de formas diferentes, e tem conceitos diferentes do que é "natural" e do que é "bom senso".
Os implementadores do cout e cin tiveram bom senso ao fazer isso?

int x;
cin &gt&gt x;
cout &lt&lt "Vinícius tem " &lt&lt x &lt&lt " anos";

Além do mais, não se pode esperar que todos numa equipe tenham experiência e nem bom-senso. Um dos pontos fortes do Java é que, com pouco esfoço, você pode entender o que um programa está fazendo. Os métodos tem nomes explícitos. A própria sun estimulou a clareza do código ao fornecer uma api com pouquíssimas abreviações. Nada de strcat e sim String.concat. A comunidade como um todo seguiu essa filosofia.

Então, me questiono. Até que ponto perder a vantagem da sobrecarga é realmente um benefício? Perder a clareza não pode trazer mais mal do que bem? Vi algumas pessoas falando que outras linguagens são mais rebuscadas e que portanto o java tem “espaço” para isso, mas isso é realmente uma vantagem?

Muita gente pode alegar: "Mas é só ler a documentação e entender que o fulano já se acostuma". Ok, mas ler documentação e entender é um custo chamado "curva de aprendizado". E para interiorizar um conceito, ele terá que ler uma documentação não uma, mas duas, três ou quatro vezes. E alguém terá que manter essa documentação atualizada. Alguém aí já trabalhou num projeto com uma documentação 100% atualizada? Se você já teve problemas para entender um método sem uma boa documentação, imagine um operador sem uma boa documentação!

I

ViniGodoy:
Acho que o maior problema aqui é o seguinte.

Programadores são seres humanos.

E seres humanos pensam de formas diferentes, e tem conceitos diferentes do que é "natural" e do que é "bom senso".
Os implementadores do cout e cin tiveram bom senso ao fazer isso?

int x;
cin &gt&gt x;
cout &lt&lt "Vinícius tem " &lt&lt x &lt&lt " anos";

Além do mais, não se pode esperar que todos numa equipe tenham experiência e nem bom-senso. Um dos pontos fortes do Java é que, com pouco esfoço, você pode entender o que um programa está fazendo. Os métodos tem nomes explícitos. A própria sun estimulou a clareza do código ao fornecer uma api com pouquíssimas abreviações. Nada de strcat e sim String.concat. A comunidade como um todo seguiu essa filosofia.

Então, me questiono. Até que ponto perder a vantagem da sobrecarga é realmente um benefício? Perder a clareza não pode trazer mais mal do que bem? Vi algumas pessoas falando que outras linguagens são mais rebuscadas e que portanto o java tem “espaço” para isso, mas isso é realmente uma vantagem?

Muita gente pode alegar: "Mas é só ler a documentação e entender que o fulano já se acostuma". Ok, mas ler documentação e entender é um custo chamado "curva de aprendizado". E para interiorizar um conceito, ele terá que ler uma documentação não uma, mas duas, três ou quatro vezes. E alguém terá que manter essa documentação atualizada. Alguém aí já trabalhou num projeto com uma documentação 100% atualizada? Se você já teve problemas para entender um método sem uma boa documentação, imagine um operador sem uma boa documentação!

Onde eu assino ?

israelins

Concordo com a sobrecarga!!!
Não acho que o código fica mais confuso acho q por default não deveria haver e dar erro de compilação… e somente ter sobrecarga classes onde fosse obvio seu uso, números, string, etc.

PolynomialFunction a = new PolynomialFunction();
	PolynomialFunction b = new PolynomialFunction();
	PolynomialFunction sum = null;
	PolynomialFunction mult = null;
	
	...
	
            // sem sobrecarga
	sum = PolynomialFunction.sum(a, b);
	mult = PolynomialFunction.mult(a, b);
            // com sobrecarga
	sum = a + b;
	mult = a * b;
	
	...
Criado 26 de julho de 2007
Ultima resposta 6 de mai. de 2009
Respostas 53
Participantes 18