A sobrecarga de operadores em C ++ é considerada por muitos como A Bad Thing (tm) e um erro que não deve ser repetido em idiomas mais novos. Certamente, esse foi um recurso descartado especificamente ao projetar Java.
Agora que comecei a ler o Scala, acho que ele tem o que se parece muito com sobrecarga de operador (embora tecnicamente não tenha sobrecarga de operador porque não possui operadores, apenas funções). No entanto, não parece ser qualitativamente diferente da sobrecarga de operadores em C ++, onde, pelo que me lembro, os operadores são definidos como funções especiais.
Então, minha pergunta é o que torna a idéia de definir "+" no Scala uma idéia melhor do que em C ++?
c++
scala
operator-overloading
skaffman
fonte
fonte
Respostas:
C ++ herda operadores azuis verdadeiros de C. Com isso, quero dizer que o "+" em 6 + 4 é muito especial. Você não pode, por exemplo, obter um ponteiro para essa função +.
Scala, por outro lado, não tem operadores dessa maneira. Ele possui grande flexibilidade na definição de nomes de métodos, além de um pouco de precedência incorporada para símbolos que não são de palavras. Portanto, tecnicamente, o Scala não possui sobrecarga de operador.
Como você quiser chamá-lo, a sobrecarga do operador não é inerentemente ruim, mesmo em C ++. O problema é quando maus programadores abusam dele. Mas, francamente, sou da opinião de que tirar a capacidade dos programadores de abusar da sobrecarga do operador não prejudica a correção de tudo o que os programadores podem abusar. A verdadeira resposta é orientação. http://james-iry.blogspot.com/2009/03/operator-overloading-ad-absurdum.html
Não obstante, existem diferenças entre a sobrecarga de operadores do C ++ e a nomeação flexível de métodos do Scala que, IMHO, tornam o Scala menos abusivo e mais abusivo.
No C ++, a única maneira de obter a notação de correção é usando operadores. Caso contrário, você deve usar object.message (argumento) ou ponteiro-> messsage (argumento) ou função (argumento1, argumento2). Portanto, se você deseja um determinado estilo DSLish no seu código, há pressão para usar operadores.
No Scala, você pode obter notação infix com qualquer mensagem enviada. "argumento de mensagem de objeto" está perfeitamente correto, o que significa que você não precisa usar símbolos que não sejam de palavras apenas para obter notação infix.
A sobrecarga do operador C ++ é limitada essencialmente aos operadores C. Combinado com a limitação de que apenas operadores podem ser usados infixos que pressionam as pessoas a tentar mapear uma ampla gama de conceitos não relacionados em relativamente poucos símbolos como "+" e ">>"
O Scala permite uma grande variedade de símbolos válidos que não sejam palavras como nomes de métodos. Por exemplo, eu tenho um DSL Prolog-ish incorporado onde você pode escrever
Os símbolos: -,!,? E & são definidos como métodos comuns. Somente em C ++ e seria válido, portanto, uma tentativa de mapear esse DSL em C ++ exigiria alguns símbolos que já evocam conceitos muito diferentes.
Claro, isso também abre Scala para outro tipo de abuso. No Scala, você pode nomear um método como $! & ^%, Se desejar.
Para outras linguagens que, como Scala, são flexíveis no uso de nomes de funções e métodos que não sejam palavras, consulte Smalltalk, onde, como Scala, todo "operador" é apenas outro método e Haskell, que permite ao programador definir precedência e fixidez de nomes flexíveis. funções.
fonte
int main() {return (3).operator+(5);}
resulta emerror: request for member ‘operator+’ in ‘3’, which is of non-class type ‘int’
Somente pelos ignorantes. É absolutamente necessário em uma linguagem como C ++, e é notável que outras linguagens que começaram a adotar uma visão "purista" a adicionaram quando seus designers descobriram o quão necessário é.
fonte
A sobrecarga do operador nunca foi universalmente considerada uma má idéia em C ++ - apenas o abuso da sobrecarga do operador foi uma má idéia. Não é realmente necessário sobrecarregar o operador em um idioma, pois eles podem ser simulados com mais chamadas de função detalhadas. Evitar a sobrecarga do operador em Java tornou a implementação e a especificação do Java um pouco mais simples e forçou os programadores a não abusar dos operadores. Houve algum debate na comunidade Java sobre a introdução de sobrecarga do operador.
As vantagens e desvantagens da sobrecarga de operadores no Scala são as mesmas que no C ++ - você pode escrever um código mais natural se usar a sobrecarga de operador adequadamente - e um código oculto e oculto, se não o fizer.
FYI: Os operadores não são definidos como funções especiais em C ++, eles se comportam como qualquer outra função - embora existam algumas diferenças na pesquisa de nome, se precisam ser funções-membro e o fato de poderem ser chamadas de duas maneiras: 1 ) sintaxe do operador e 2) sintaxe do operador-função-ID.
fonte
add(2, multiply(5, 3))
?Este artigo - " O legado positivo de C ++ e Java " - responde diretamente à sua pergunta.
O Java erroneamente (de acordo com o autor) omitiu a sobrecarga do operador porque era complicado em C ++, mas esqueceu o porquê (ou não percebeu que não se aplicava ao Java).
Felizmente, linguagens de nível superior como o Scala oferecem opções para desenvolvedores, enquanto ainda estão em execução na mesma JVM.
fonte
Não há nada errado com a sobrecarga do operador. De fato, há algo errado em não haver sobrecarga de operador para tipos numéricos. (Dê uma olhada em algum código Java que usa BigInteger e BigDecimal.)
C ++ tem uma tradição de abusar do recurso, no entanto. Um exemplo frequentemente citado é que os operadores de deslocamento de bits estão sobrecarregados para fazer E / S.
fonte
=
vez de<<
e>>
nos primeiros dias do C ++, mas teve problemas porque não tinha a precedência correta do operador (ou seja, procura argumentos à esquerda ou à direita primeiro). Então, suas mãos estavam um pouco atadas sobre o que ele poderia usar.Em geral, não é uma coisa ruim.
Novos idiomas como C # também têm sobrecarga de operador.
É o abuso de sobrecarga do operador que é uma coisa ruim.
Mas também há problemas com a sobrecarga do operador, conforme definido em C ++. Como os operadores sobrecarregados são apenas açúcar sintático para chamadas de método, eles se comportam exatamente como o método. Por outro lado, os operadores internos normais não se comportam como métodos. Essas inconsistências podem causar problemas.
Em cima da minha cabeça operadores
||
e&&
.As versões integradas destes são operadores de atalho. Isso não é verdade para versões sobrecarregadas e causou alguns problemas.
O fato de que + - * / todos retornam o mesmo tipo em que operam (após a promoção do operador)
As versões sobrecarregadas podem retornar qualquer coisa (é aqui que o abuso ocorre, se os operadores começarem a retornar algum tipo de árbitro que o usuário não esperava) as coisas descem).
fonte
Sobrecarga de operador não é algo que você realmente "precise" com muita frequência, mas ao usar Java, se você atingir um ponto em que realmente precisa, isso fará com que você queira arrancar as unhas apenas para ter uma desculpa para parar de digitar .
O código que você acabou de encontrar transborda por muito tempo? Sim, você precisará redigitar todo o lote para que funcione com o BigInteger. Não há nada mais frustrante que ter que reinventar a roda apenas para mudar o tipo de uma variável.
fonte
Guy Steele argumentou que a sobrecarga do operador também deveria estar em Java, em seu discurso "Crescendo uma linguagem" - há um vídeo e uma transcrição, e é realmente um discurso incrível. Você se perguntará sobre o que ele está falando nas primeiras páginas, mas se continuar lendo, verá o ponto e alcançará a iluminação. E o próprio fato de ele poder fazer esse discurso também é incrível.
Ao mesmo tempo, essa palestra inspirou muitas pesquisas fundamentais, provavelmente incluindo Scala - é um daqueles artigos que todos deveriam ler para trabalhar no campo.
De volta ao ponto, seus exemplos são principalmente sobre classes numéricas (como BigInteger e algumas coisas mais estranhas), mas isso não é essencial.
É verdade, porém, que o uso indevido da sobrecarga do operador pode levar a resultados terríveis e que mesmo os usos adequados podem complicar as coisas, se você tentar ler o código sem estudar um pouco as bibliotecas que ele usa. Mas isso é uma boa ideia? OTOH, essas bibliotecas não deveriam tentar incluir uma cábula de operador para seus operadores?
fonte
Acredito que CADA resposta perdeu isso. No C ++, você pode sobrecarregar os operadores o quanto quiser, mas não pode afetar a precedência com a qual eles são avaliados. Scala não tem esse problema, IIRC.
Por ser uma má idéia, além das questões de precedência, as pessoas criam significados realmente tolos para os operadores, e isso raramente ajuda na legibilidade. As bibliotecas Scala são especialmente ruins para isso, símbolos patetas que você deve memorizar a cada vez, com os mantenedores da biblioteca enfiando a cabeça na areia dizendo: 'você só precisa aprender uma vez'. Ótimo, agora eu preciso aprender a sintaxe enigmática de algum autor 'inteligente' * o número de bibliotecas que gostaria de usar. Não seria tão ruim se existisse uma convenção de SEMPRE fornecer uma versão alfabética dos operadores.
fonte
A sobrecarga do operador não era uma invenção do C ++ - veio do Algol IIRC e até Gosling não afirma que é uma má ideia em geral.
fonte
A única coisa que se sabe de errado no C ++ é a falta de capacidade de sobrecarregar [] = como um operador separado. Isso pode ser difícil de implementar em um compilador C ++ pelo que provavelmente não é um motivo óbvio, mas vale a pena.
fonte
Como as outras respostas apontaram; sobrecarregar o operador não é necessariamente ruim. O que é ruim quando é usado de maneiras que tornam o código resultante não óbvio. Geralmente, ao usá-los, você precisa fazê-los fazer a coisa menos surpreendente (ter a divisão operator + do causaria problemas para o uso de uma classe racional) ou como Scott Meyers diz:
Agora, algumas pessoas levaram a sobrecarga do operador ao extremo com coisas como boost :: spirit . Nesse nível, você não tem idéia de como é implementado, mas cria uma sintaxe interessante para obter o que deseja. Não tenho certeza se isso é bom ou ruim. Parece bom, mas eu não o usei.
fonte
Eu nunca vi um artigo alegando que a sobrecarga de operador do C ++ seja ruim.
Os operadores definidos pelo usuário permitem um nível mais alto de expressividade e usabilidade para os usuários do idioma.
fonte
AFAIK, Não há nada de especial nas funções do operador em comparação com as funções de membro "normais". É claro que você só tem um determinado conjunto de operadores que pode sobrecarregar, mas isso não os torna muito especiais.
fonte