Eu não entendo os argumentos contra sobrecarga de operador [fechado]

82

Acabei de ler um dos artigos de Joel em que ele diz:

Em geral, tenho que admitir que tenho um pouco de medo de recursos de linguagem que ocultam as coisas . Quando você vê o código

i = j * 5;

... em C, você sabe, pelo menos, que j está sendo multiplicado por cinco e os resultados armazenados em i.

Mas se você vir esse mesmo trecho de código em C ++, não saberá nada. Nada. A única maneira de saber o que realmente está acontecendo no C ++ é descobrir quais são os tipos iej, algo que pode ser declarado em outro lugar. Isso porque j pode ser de um tipo que tenha operator*sobrecarregado e faz algo terrivelmente espirituoso quando você tenta multiplicá-lo.

(Ênfase minha.) Com medo de recursos de linguagem que ocultam as coisas? Como você pode ter medo disso? Ocultar coisas (também conhecidas como abstração ) não é uma das idéias principais da programação orientada a objetos? Sempre que você chama um método a.foo(b), você não tem idéia do que isso pode fazer. Você precisa descobrir quais tipos ae quais bsão, algo que pode ser declarado em algum outro lugar. Então, devemos acabar com a programação orientada a objetos, porque esconde muitas coisas do programador?

E como é j * 5diferente de j.multiply(5)qual você pode escrever em um idioma que não suporta sobrecarga de operador? Novamente, você teria que descobrir o tipo je espiar dentro do multiplymétodo, porque eis que ele jpode ser de um tipo que possui um multiplymétodo que faz algo terrivelmente espirituoso.

"Muahaha, sou um programador malvado que nomeia um método multiply, mas o que ele realmente faz é totalmente obscuro e não intuitivo e não tem absolutamente nada a ver com a multiplicação das coisas". Esse é um cenário que devemos levar em consideração ao projetar uma linguagem de programação? Então, temos que abandonar identificadores de linguagens de programação com o argumento de que eles podem ser enganosos!

Se você quiser saber o que um método faz, pode dar uma olhada na documentação ou espiar dentro da implementação. Sobrecarga de operador é apenas açúcar sintático, e não vejo como isso muda o jogo.

Por favor me esclareça.

fredoverflow
fonte
20
+1: Bem escrito, bem argumentado, tópico interessante e altamente discutível. Um exemplo brilhante de uma pergunta p.se.
Allon Guralnek
19
+1: As pessoas ouvem Joel Spolsky porque ele escreve bem e é bem conhecido. Mas isso não o faz acertar 100% do tempo. Eu concordo com o seu argumento. Se todos seguíssemos a lógica de Joel aqui, nunca chegaríamos a lugar algum.
Ninguém
5
Eu diria que i e j são declarados localmente para que você possa ver rapidamente o tipo deles, ou eles são nomes de variáveis ​​ruins e devem ser renomeados adequadamente.
Cameron MacFarland
5
+1, mas não se esqueça da melhor parte do artigo de Joel: depois de correr uma maratona em direção à resposta correta, ele, sem motivo aparente, para 50 pés antes dela. Código incorreto não deve parecer errado; não deve compilar.
Larry Coleman
3
@ Larry: Você pode fazer com que o código errado falhe na compilação, definindo as classes de maneira adequada; portanto, no exemplo dele, você pode ter SafeString e UnsafeString em C ++, ou RowIndex e ColumnIndex, mas precisará usar sobrecarga de operador para fazê-las se comportar intuitivamente.
David Thornley

Respostas:

32

A abstração 'oculta' o código para que você não precise se preocupar com o funcionamento interno e, muitas vezes, para não poder alterá-lo, mas a intenção não era impedir que você o visse. Apenas fazemos suposições sobre os operadores e, como Joel disse, pode estar em qualquer lugar. Ter um recurso de programação que exija que todos os operadores sobrecarregados sejam estabelecidos em um local específico pode ajudar a encontrá-lo, mas não tenho certeza se isso facilita o uso.

Não vejo fazer * fazer algo que não se pareça com a multiplicação melhor do que uma função chamada Get_Some_Data que exclui dados.

JeffO
fonte
13
+1 Para o bit 'eu não vejo'. Os recursos de idioma estão disponíveis para uso, não abuso.
Michael K
5
No entanto, temos um <<operador definido em fluxos que nada tem a ver com a mudança bit a bit, diretamente na biblioteca padrão do C ++.
Malcolm
o operador 'deslocamento bit a bit' é chamado apenas por razões históricas. Quando aplicado a tipos padrão, ele faz uma mudança bit a bit (da mesma maneira que o operador + adiciona números quando aplicado a tipos numéricos); no entanto, quando aplicado a um tipo complexo, ele pode fazer o que quiser, desde que faça sentido para esse tipo.
Gbjbaanb
1
* também é usado para desreferenciar (como feito por ponteiros e iteradores inteligentes); não está claro onde colocar o limite entre o bem eo mal sobrecarga
martinkunev
Não seria em qualquer lugar, estaria na definição de tipo de j.
Andy
19

IMHO, recursos de linguagem como sobrecarga do operador dão ao programador mais poder. E, como todos sabemos, com grande poder vem uma grande responsabilidade. Os recursos que lhe dão mais poder também oferecem mais maneiras de dar um tiro no próprio pé e, obviamente, devem ser usados ​​criteriosamente.

Por exemplo, faz todo o sentido sobrecarregar +o *operador ou o operador class Matrixor class Complex. Todos saberão instantaneamente o que isso significa. Por outro lado, para mim, o fato de +significar concatenação de strings não é de todo óbvio, mesmo que Java faça isso como parte da linguagem e STL faça por std::stringusar sobrecarga de operador.

Outro bom exemplo de quando a sobrecarga do operador torna o código mais claro são os ponteiros inteligentes em C ++. Você deseja que os ponteiros inteligentes se comportem como ponteiros regulares o máximo possível, por isso faz todo o sentido sobrecarregar os unários *e os ->operadores.

Em essência, a sobrecarga do operador nada mais é do que outra maneira de nomear uma função. E existe uma regra para nomear funções: o nome deve ser descritivo, tornando imediatamente óbvio o que a função faz. A mesma regra exata se aplica à sobrecarga do operador.

Dima
fonte
1
Suas duas últimas frases chegam ao cerne da objeção à sobrecarga do operador: o desejo de que todo o código seja imediatamente óbvio.
Larry Coleman
2
Não é óbvio o que M * N significa, onde M e N são do tipo Matrix?
Dima
2
@ Fred: Não. Existe um tipo de multiplicação de matrizes. Você pode multiplicar uma matriz mxn por uma matriz nxk e obter uma matriz mxk.
Dima
1
@FredOverflow: Existem diferentes maneiras de multiplicar um vetor tridimensional, um dando a você um escalar e outro dando a outro vetor tridimensional e, portanto, sobrecarregá *-los pode causar confusão. Pode-se argumentar que você poderia usar operator*()o produto escalar e operator%()o produto cruzado, mas eu não faria isso em uma biblioteca de uso geral.
David Thornley
2
@ Martin Beckett: No. C ++ não é permitido para reordenar A-Bcomo B-Aseja, e todos os operadores seguir aquele padrão. Embora sempre exista uma exceção: quando o compilador pode provar que não importa, é permitido reorganizar tudo.
Sjoerd
9

No Haskell "+", "-", "*", "/" etc são apenas funções (infix).

Você deve nomear uma função infix "mais" como em "4 mais 2"? Por que não, se adição é o que sua função faz. Você deve nomear sua função "mais" como "+"? Por que não.

Penso que o problema com os chamados "operadores" é que eles se assemelham principalmente a operações matemáticas e não existem muitas maneiras de interpretá-las e, portanto, há grandes expectativas sobre o que esse método / função / operador faz.

EDIT: deixou meu argumento mais claro

LennyProgrammers
fonte
Erm, exceto pelo que é herdado de C, C ++ (e é sobre isso que Fred estava perguntando) faz praticamente a mesma coisa. Agora, o que você pensa se isso é bom ou ruim?
SBI
@sbi Eu amo sobrecarga de operadores ... operadores Na verdade, mesmo C tem sobrecarregados ... Você pode usá-los para int, float, long longe qualquer que seja. Então, o que é isso tudo?
FUZxxl
@FUZxxl: trata -se de operadores definidos pelo usuário que sobrecarregam os integrados.
S11
1
@sbi Haskell não faz distinção entre interno e definido pelo usuário . Todos os operadores são iguais. Você pode até ativar algumas extensões que removem todos os itens predefinidos e permitem que você escreva qualquer coisa do zero, incluindo quaisquer operadores.
FUZxxl
@FUZxxl: Pode ser, mas aqueles que se opõem a operadores sobrecarregados geralmente não se opõem ao uso interno +para diferentes tipos de números internos, mas à criação de sobrecargas definidas pelo usuário. daqui meu comentário.
S11
7

Com base nas outras respostas que já vi, só posso concluir que a verdadeira objeção à sobrecarga do operador é o desejo de código imediatamente óbvio.

Isso é trágico por dois motivos:

  1. Levado a sua conclusão lógica, o princípio de que o código deveria ser imediatamente óbvio teria todos nós ainda codificando em COBOL.
  2. Você não aprende com o código que é imediatamente óbvio. Você aprende com o código que faz sentido depois de dedicar algum tempo para pensar em como ele funciona.
Larry Coleman
fonte
Aprender com o código nem sempre é o objetivo principal. Em um caso como "o recurso X está com falha, a pessoa que o escreveu deixou a empresa e você precisa corrigi-lo o mais rápido possível", prefiro ter um código imediatamente óbvio.
Errorsatz
5

Eu concordo um pouco.

Se você escrever multiply(j,5), jpode ser do tipo escalar ou matriz, tornando-se multiply()mais ou menos complexo, dependendo do que jé. No entanto, se você abandonar completamente a idéia de sobrecarregar, a função terá que ser nomeada multiply_scalar()ou o multiply_matrix()que tornaria óbvio o que está acontecendo por baixo.

Há código em que muitos de nós preferiríamos de uma maneira e há código em que a maioria de nós preferia de outra maneira. A maior parte do código, no entanto, cai no meio termo entre esses dois extremos. O que você prefere depende do seu histórico e preferências pessoais.

sbi
fonte
Bom ponto. No entanto, abandonando sobrecarregar completamente não jogar bonito com programação genérica ...
fredoverflow
@ Fred: Claro que não. Mas a programação genérica tem tudo a ver com usar o mesmo algoritmo para tipos muito diferentes; portanto, aqueles que preferem multiply_matrix()também não gostam de programação genérica.
S10 /
2
Você é bastante otimista sobre nomes, não é? Com base em alguns lugares em que trabalhei, esperaria nomes como 'multiply () `e' multiplym ()` ou talvez mais real_multiply()ou menos. Os desenvolvedores geralmente não são bons com nomes e operator*()pelo menos serão consistentes.
David Thornley
@ David: Sim, eu pulei o fato de que os nomes podem ser ruins. Mas, então, podemos também supor que isso operator*()possa fazer algo estúpido, jé uma macro avaliada para expressões que envolvem cinco chamadas de função e outras coisas. Então você não pode mais comparar as duas abordagens. Mas, sim, nomear bem as coisas é difícil, embora valha a pena o tempo que for necessário.
S10 /
5
@ David: E como nomear as coisas é difícil, os nomes devem ser banidos das linguagens de programação, certo? É muito fácil errar! ;-)
fredoverflow
4

Eu vejo dois problemas com sobrecarga do operador.

  1. A sobrecarga altera a semântica do operador, mesmo que isso não seja pretendido pelo programador. Por exemplo, quando você sobrecarregar &&, ||ou ,, você perde os pontos de seqüência que estão implícitas pelas variantes embutidos destes operadores (bem como o comportamento de curto-circuito dos operadores lógicos). Por esse motivo, é melhor não sobrecarregar esses operadores, mesmo que o idioma permita.
  2. Algumas pessoas veem a sobrecarga do operador como um recurso tão bom que começam a usá-lo em qualquer lugar, mesmo que não seja a solução apropriada. Isso faz com que outras pessoas reajam demais na outra direção e alertam contra o uso de sobrecarga do operador. Não concordo com nenhum dos grupos, mas tome o meio termo: a sobrecarga do operador deve ser usada com moderação e somente quando
    • o operador sobrecarregado tem o significado natural para os especialistas em domínio e os especialistas em software. Se esses dois grupos não concordarem com o significado natural para o operador, não o sobrecarregue.
    • para o (s) tipo (s) envolvido (s), não há significado natural para o operador e o contexto imediato (de preferência a mesma expressão, mas não mais do que algumas linhas) sempre deixa claro qual é o significado do operador. Um exemplo dessa categoria seria operator<<para fluxos.
Bart van Ingen Schenau
fonte
1
+1 de mim, mas o segundo argumento também pode ser aplicado à herança. Muitas pessoas não têm idéia sobre herança e tentam aplicá-la a tudo. Eu acho que a maioria dos programadores concorda que é possível usar de maneira incorreta a herança. Isso significa que a herança é "má" e deve ser abandonada das linguagens de programação? Ou devemos deixá-lo como também pode ser útil?
Fredoverflow
@FredOverflow O segundo argumento pode ser aplicado a qualquer coisa que seja "nova e quente". Não estou dando como argumento para remover a sobrecarga do operador de uma linguagem, mas como uma razão pela qual as pessoas argumentam contra. Para mim, a sobrecarga do operador é útil, mas deve ser usada com cuidado.
Bart van Ingen Schenau
IMHO, permitir sobrecargas &&e ||de uma maneira que não implique seqüenciamento foi um grande erro (IMHO, se o C ++ permitiria a sobrecarga desses, ele deveria ter usado um formato especial de "duas funções", com a primeira função sendo necessária para retornar um tipo implicitamente conversível em um número inteiro; a segunda função pode receber dois ou três argumentos, com o argumento "extra" da segunda função sendo o tipo de retorno do primeiro. O compilador chamaria a primeira função e, em seguida, se ele voltou diferente de zero, avaliar o segundo operando e chamar a segunda função em cima dele).
supercat
Obviamente, isso não é tão bizarro quanto permitir que o operador de vírgula seja sobrecarregado. Aliás, uma coisa sobrecarregada que eu realmente não vi, mas gostaria de, seria um meio de acesso restrito a membros, permitindo que uma expressão foo.bar[3].Xfosse tratada pela fooclasse de, em vez de exigir fooexpor um membro que pode oferecer suporte à assinatura e expor um membro X. Se alguém quisesse forçar a avaliação via acesso real dos membros, escreveria ((foo.bar)[3]).X.
Supercat 19/07
3

Com base na minha experiência pessoal, a maneira Java de permitir vários métodos, mas não sobrecarregar o operador, significa que sempre que você vê um operador, sabe exatamente o que ele faz.

Você não precisa ver se *chama um código estranho, mas sabe que é uma multiplicação e se comporta exatamente como na maneira definida pela Especificação de Linguagem Java. Isso significa que você pode se concentrar no comportamento real em vez de descobrir todas as coisas definidas pelo programador.

Em outras palavras, proibir a sobrecarga do operador é um benefício para o leitor , não para o gravador e, portanto, facilita a manutenção dos programas!


fonte
+1, com uma ressalva: C ++ fornece corda suficiente para você se enforcar. Mas se eu quiser implementar uma lista vinculada em C ++, gostaria da capacidade de usar [] para acessar o enésimo elemento. Faz sentido usar os operadores para dados para os quais (matematicamente falando) são válidos.
Michael K
@ Michael, você não pode viver com a list.get(n)sintaxe?
@ Thorbjørn: Na verdade, também está bem, talvez um péssimo exemplo. O tempo pode ser melhor - sobrecarregar +, - faria sentido, em vez de time.add (anotherTime).
Michael K
4
@ Michael: Sobre listas vinculadas, std::listnão sobrecarrega operator[](ou fornece qualquer outro meio de indexação na lista), porque essa operação seria O (n), e uma interface de lista não deve expor essa função se você se preocupa com a eficiência. Os clientes podem ficar tentados a repetir listas vinculadas com índices, tornando os algoritmos O (n) desnecessariamente O (n ^ 2). Você vê isso frequentemente no código Java, especialmente se as pessoas trabalham com a Listinterface que visa abstrair completamente a complexidade.
Fredoverflow
5
@ Thor: "Mas, para ter certeza, você precisa verificar :)" ... Novamente, isso não está ligado à sobrecarga do operador . Se você time.add(anotherTime)vir, também precisará verificar se o programador da biblioteca implementou a operação de adição "corretamente" (o que isso significa).
Fredoverflow
3

Uma diferença entre sobrecarga a * be chamada multiply(a,b)é que a última pode ser facilmente recebida. Se a multiplyfunção não estiver sobrecarregada para tipos diferentes, você poderá descobrir exatamente o que a função fará, sem precisar rastrear os tipos de ae b.

Linus Torvalds tem um argumento interessante sobre a sobrecarga do operador. Em algo como o desenvolvimento do kernel Linux, onde a maioria das alterações é enviada por meio de correções por email, é importante que os mantenedores possam entender o que um patch fará com apenas algumas linhas de contexto em torno de cada alteração. Se funções e operadores não estiverem sobrecarregados, o patch poderá ser lido com mais facilidade de maneira independente do contexto, pois você não precisará examinar o arquivo alterado para descobrir quais são todos os tipos e verificar se há operadores sobrecarregados.

Scott Wales
fonte
O kernel linux não é desenvolvido em C puro? Por que discutir sobrecarga (operador) neste contexto?
Fredoverflow
As preocupações são as mesmas para qualquer projeto com um processo de desenvolvimento semelhante, independentemente do idioma. Sobrecarga excessiva pode dificultar a compreensão do impacto das alterações se tudo o que você precisa é seguir algumas linhas de um arquivo de patch.
Scott Wales
@FredOverflow: O kernel do Linux está realmente no GCC C. Ele usa todos os tipos de extensões que dão ao seu C uma sensação quase C ++ em alguns momentos. Estou pensando em algumas das manipulações sofisticadas.
Zan Lynx
2
@ Scott: Não faz sentido discutir a "maldade" da sobrecarga em relação aos projetos programados em C, porque C não tem a capacidade de sobrecarregar funções.
Fredoverflow
3
Linus Torvalds me parece ter um ponto de vista estreito. Ele às vezes critica coisas que não são realmente úteis para a programação do kernel Linux como se isso as tornasse inadequadas para uso geral. Subversion é um exemplo. É um bom VCS, mas o desenvolvimento do kernel do Linux realmente precisa de um VCS distribuído, então Linus criticou o SVN em geral.
David Thornley
2

Suspeito que tenha algo a ver com quebrar expectativas. Já estou acostumado a C ++, o comportamento do operador não é totalmente determinado pela linguagem e você não ficará surpreso quando um operador fizer algo estranho. Se você está acostumado a idiomas que não possuem esse recurso e vê o código C ++, traz consigo as expectativas desses outros idiomas e pode se surpreender ao descobrir que um operador sobrecarregado faz algo estranho.

Pessoalmente, acho que há uma diferença. Quando você pode alterar o comportamento da sintaxe interna do idioma, torna-se mais opaco para se pensar. Os idiomas que não permitem a metaprogramação são sintaticamente menos poderosos, mas conceitualmente mais simples de entender.

Joeri Sebrechts
fonte
Operadores sobrecarregados nunca devem fazer "algo estranho". Tudo bem se fizer algo complexo, é claro. Mas apenas sobrecarrega quando tem um significado óbvio.
Sjoerd
2

Eu acho que sobrecarregar operadores matemáticos não é o problema real da sobrecarga de operadores em C ++. Eu acho que sobrecarregar operadores que não devem confiar no contexto da expressão (ou seja, tipo) é "mau". Por exemplo, sobrecarga , [ ] ( ) -> ->* new deleteou mesmo o unário *. Você tem um certo conjunto de expectativas daqueles operadores que nunca devem mudar.

Allon Guralnek
fonte
+1 Não faça [] o equivalente a ++.
Michael K
3
Você está dizendo que não deve ser capaz de sobrecarregar os operadores que você mencionou em tudo ? Ou você está apenas dizendo que devemos sobrecarregá-los apenas para fins sãos? Porque eu odiaria ver contêineres sem operator[], functors sem operator(), ponteiros inteligentes sem operator->e assim por diante.
Fredoverflow
Estou dizendo que o problema potencial de sobrecarga de operadores com operações matemáticas é pequeno em comparação com esses operadores. Fazer algo inteligente ou louco com operadores matemáticos pode ser problemático, mas os operadores que listei, que as pessoas geralmente não consideram operadores, mas elementos básicos da linguagem, devem sempre atender às expectativas definidas pela linguagem. []deve sempre ser um acessador do tipo matriz e ->deve sempre significar acessar um membro. Não importa se é realmente uma matriz ou um contêiner diferente, ou se é um ponteiro inteligente ou não.
Allon Guralnek
2

Entendo perfeitamente que você não gosta do argumento de Joel sobre se esconder. Nem eu. É realmente muito melhor usar '+' para coisas como tipos numéricos incorporados ou para os seus próprios, como, por exemplo, matriz. Admito que isso é puro e elegante para poder multiplicar duas matrizes com o '*' em vez de '.multiply ()'. E, afinal, temos o mesmo tipo de abstração nos dois casos.

O que dói aqui é a legibilidade do seu código. Na vida real, não no exemplo acadêmico de multiplicação de matrizes. Especialmente se a sua linguagem permitir definir operadores que não estão presentes inicialmente no núcleo da linguagem, por exemplo =:=. Muitas perguntas extras surgem neste momento. O que é esse maldito operador? Quero dizer, qual é a precedência dessa coisa? Qual é a associatividade? Em que ordem é a =:= b =:= crealmente executada?

Esse já é um argumento contra a sobrecarga do operador. Ainda não está convencido? Verificar as regras de precedência levou mais de 10 segundos? Ok, vamos mais longe.

Se você começar a usar uma linguagem que permita a sobrecarga do operador, por exemplo, a popular cujo nome começa com 'S', você aprenderá rapidamente que os designers de bibliotecas gostam de substituir os operadores. É claro que eles são bem-educados, seguem as melhores práticas (sem cinismo aqui) e todas as suas APIs fazem todo sentido quando as olhamos separadamente.

Agora imagine que você precisa usar algumas APIs que fazem uso pesado de operadores que sobrecarregam juntos em um único pedaço de código. Ou melhor ainda - você precisa ler um código legado como esse. É quando a sobrecarga do operador é realmente péssima. Basicamente, se houver muitos operadores sobrecarregados em um local, eles logo começarão a se misturar com os outros caracteres não alfanuméricos no código do programa. Eles se misturam com caracteres não alfanuméricos que não são realmente operadores, mas com alguns elementos gramaticais de linguagem mais fundamentais que definem coisas como blocos e escopos, modelam instruções de controle de fluxo ou denotam algumas meta-coisas. Você precisará colocar os óculos e aproximar os olhos 10 cm da tela LCD para entender essa bagunça visual.

akosicki
fonte
1
Sobrecarregar operadores existentes e inventar novos operadores não é a mesma coisa, mas +1 de mim.
Fredoverflow 16/04/2015
1

Em geral, evito usar a sobrecarga do operador de maneiras não intuitivas. Ou seja, se eu tiver uma classe numérica, a sobrecarga * é aceitável (e incentivada). No entanto, se eu tiver uma classe Employee, o que sobrecarregar * faria? Em outras palavras, sobrecarregue os operadores de maneiras intuitivas que facilitam a leitura e a compreensão.

Aceitável / Incentivado:

class Complex
{
public:
    double r;
    double i;

    Complex operator*(const Compex& rhs)
    {
        Complex result;
        result.r = (r * rhs.r) - (i * rhs.i);
        result.i = (r * rhs.i) + (i * rhs.r);
        return result;
    }
};

Não aceitável:

class Employee
{
public:
    std::string name;
    std::string address;
    std::string phone_number;

    Employee operator* (const Employee& e)
    {
        // what the hell do I do here??
    }
};
Zac Howland
fonte
1
Multiplicando funcionários? Certamente isso é uma ofensa insaciável, se eles o fazem na mesa da sala de reuniões, é isso.
Gbjbaanb
1

Além do que já foi dito aqui, há mais um argumento contra a sobrecarga do operador. De fato, se você escreve +, isso é óbvio que você quer dizer adição de algo a algo. Mas nem sempre é esse o caso.

O próprio C ++ fornece um ótimo exemplo desse caso. Como stream << 1deve ser lido? fluxo mudou para a esquerda por 1? Não é óbvio, a menos que você saiba explicitamente que << em C ++ também grava no fluxo. No entanto, se essa operação fosse implementada como um método, nenhum desenvolvedor sadio escreveria o.leftShift(1), seria algo parecido o.write(1).

A conclusão é que, ao tornar a sobrecarga do operador indisponível, a linguagem faz com que os programadores pensem nos nomes das operações. Mesmo que o nome escolhido não seja perfeito, ainda é mais difícil interpretar um nome do que um sinal.

Malcolm
fonte
1

Em comparação aos métodos detalhados, os operadores são mais curtos, mas também não exigem parênteses. Parênteses são relativamente inconvenientes para digitar. E você deve equilibrá-los. No total, qualquer chamada de método requer três caracteres de ruído simples em comparação com um operador. Isso torna o uso de operadores muito, muito tentador.
Por que mais alguém iria querer isso cout << "Hello world":?

O problema com a sobrecarga é que a maioria dos programadores é incrivelmente preguiçosa e a maioria dos programadores não pode se dar ao luxo de ser.

O que leva os programadores de C ++ a abusar da sobrecarga do operador não é a sua presença, mas a ausência de uma maneira mais clara de executar chamadas de método. E as pessoas não têm apenas medo de sobrecarregar o operador porque isso é possível, mas porque está feito.
Observe que, por exemplo, em Ruby e Scala, ninguém tem medo de sobrecarregar o operador. Além do fato de que o uso de operadores não é realmente mais curto que os métodos, outro motivo é que Ruby limita a sobrecarga de operadores a um mínimo sensato, enquanto o Scala permite que você declare seus próprios operadores , evitando assim a trivialidade de colisões.

back2dos
fonte
ou, em C #, para usar + = para vincular um evento a um delegado. Não acho que culpar os recursos da linguagem pela estupidez do programador seja um caminho construtivo.
Gbjbaanb
0

A razão pela qual a Sobrecarga do operador é assustadora, é porque há um grande número de programadores que nunca pensariam que *não significa simplesmente "multiplicar", enquanto um método como foo.multiply(bar)pelo menos instantaneamente indica ao programador que alguém escreveu um método de multiplicação personalizado . Nesse momento, eles se perguntariam o porquê e iriam investigar.

Eu trabalhei com "bons programadores" que estavam em posições de alto nível que criariam métodos chamados "CompareValues" que levariam 2 argumentos e aplicariam os valores de um ao outro e retornariam um booleano. Ou um método chamado "LoadTheValues" que iria ao banco de dados para outros 3 objetos, obter valores, fazer cálculos, modificar thise salvá-lo no banco de dados.

Se estou trabalhando em uma equipe com esses tipos de programadores, sei instantaneamente investigar as coisas em que eles trabalharam. Se eles sobrecarregaram um operador, não tenho como saber que eles fizeram isso, exceto supor que eles fizeram e continuar procurando.

Em um mundo perfeito, ou em uma equipe com programadores perfeitos, a sobrecarga do operador é provavelmente uma ferramenta fantástica. Ainda tenho que trabalhar em uma equipe de programadores perfeitos, por isso é assustador.

James P. Wright
fonte