Recentemente, me deparei com perguntas sobre como prever a saída de código que usa fortemente operadores de pós / pré incremento em números inteiros. Sou programador C experiente, então me senti em casa, mas as pessoas fizeram declarações de que o Java apenas copiou cegamente o de C (ou C ++), e que esse é um recurso inútil no Java.
Dito isto, não consigo encontrar uma boa razão para isso (especialmente tendo em mente a diferença entre as formas pós / pré) em Java (ou C #), porque não é como se você manipulasse matrizes e as usasse como cadeias de caracteres em Java . Além disso, foi há muito tempo que eu analisei o bytecode pela última vez, então não sei se há uma INC
operação, mas não vejo nenhuma razão para isso.
for(int i = 0; i < n; i += 1)
poderia ser menos eficaz do que
for(int i = 0; i < n; i++)
Existe alguma parte específica da linguagem em que isso é realmente útil ou isso é apenas um recurso para trazer os programadores C para a cidade?
Respostas:
Certamente é um recurso "trazer os programadores C (ou C ++) para a cidade", mas usar a palavra "just" aqui subestima o valor dessa semelhança.
facilita o código (ou pelo menos trechos de código) da porta de C (ou C ++) para Java ou C #
i++
é menor do que digitari += 1
ex[i++]=0;
é muito mais idiomático do quex[i]=0;i+=1;
E sim, o código que usa muito operadores de pós / pré-incremento pode ser difícil de ler e manter, mas para qualquer código em que esses operadores sejam mal utilizados, eu não esperaria um aumento drástico na qualidade do código, mesmo que o idioma não os fornecesse. Isso porque se você tiver desenvolvedores que não se importam com a manutenção, eles sempre encontrarão maneiras de escrever código difícil de entender.
Relacionado: Existe alguma diferença entre os operadores Java e C ++? A partir desta resposta, pode-se deduzir que qualquer comportamento bem definido do operador em C é semelhante em Java, e Java adiciona apenas algumas definições para precedência do operador em que C tem comportamento indefinido. Isso não parece coincidência, parece bem intencional.
fonte
x[i++]=0
é idiomático em C, mas não concordo que seja idiomático em C # e Java. Com que frequência você encontra essas frases, a menos que trabalhe no domínio de engenharia / matemática, o que, presumo, não consome mais de 1% do código Java / C # em estado selvagem?Às vezes, uso o incremento do postfix nas instruções de retorno. Por exemplo, considere isso:
Você não pode fazer isso com
index += 1
. Portanto, pelo menos a versão do postfix pode salvar você de vez em quando em algumas linhas.Dito isto, esses operadores não são realmente necessários e podem confundir as pessoas. Eu sei que a Scala decidiu contra esses operadores (você tem apenas
+=
e-=
, como sugeriu), e devido à abordagem mais "de alto nível", eu realmente não sinto falta deles por lá. Espero que o Java se desenvolva (mais lentamente) na mesma direção.No entanto, o Java tem vários outros operadores que você não vê com muita frequência "na natureza" (você já usou
^=
ou>>>=
?), E ninguém se importa.fonte
^=
é razoavelmente comum. Você pode usá-lo para inverter sinalizadores de campo de bits, trocar dois números inteiros sem uma variável temporária e em alguns algoritmos de hash / cifra. Eu admito que nunca usei>>>=
, no entanto. (Então, novamente, eu nunca usei>>>
ou<<<
em qualquer programa de produção ...)Eu construí muitos idiomas ao longo dos anos, principalmente para fins especiais. O que acontece é que você tem um grande público e todos eles têm expectativas. Ao considerar cada recurso, você deve avaliar o benefício do recurso com o custo de possivelmente violar as expectativas.
Uma que eu pessoalmente tive que recuar foi a divisão de números inteiros, que normalmente trunca para baixo, certo? Tipo
3 / 2 = 1.5 = 1
né? Bem, nos primórdios de Fortran, alguém decidiu-3 / 2 = -1.5 = -1
(não -2). Em outras palavras, se o dividendo é negativo e o divisor é positivo, deve truncar -se . Observe o que isso implica - nesse caso, o restante é negativo . Isso viola a suposição usual de que o restante = módulo. Se você estiver criando gráficos, com coordenadas inteiras, isso pode levar a todos os tipos de problemas. Assim, na língua que eu simplesmente tinha inteiro truncado divisão para baixo todo o tempo, e dizer assim, no doc.E então, adivinhe o que aconteceu? Todo mundo se soltou. A linguagem teve um erro na divisão de números inteiros!
Não adiantava dizer que o caminho antigo estava quebrado. Era mais fácil mudá-lo do que argumentar.
Portanto, para responder sua pergunta, em linguagens como C # e Java, é mais fácil incluir os operadores ++ (que eu pessoalmente gosto) do que explicar por que não.
fonte
break
s necessários em cada cláusula, mesmo que a linguagem não permita que ela caia. Enquanto D descartou a compatibilidade retroativa do C ++ com o C, sua política é que qualquer construção C mantida por D surpreenda o mínimo possível o programador C.break; case ...
;-)/
produzdouble
oufloat
(usandodouble
nos casos em que ambos funcionariam) e ter operadores separados para a divisão com piso, truncada e "faça o que for", além de módulo, restante e "igualmente divisível por "[o último produzindo um booleano]. Eu diria que qualquer resultado deint x=y/z;
tem uma probabilidade significativa de diferir do que foi pretendido; portanto, a expressão não deve produzir nenhum resultado.(a+b+c)//3
na maioria dos idiomas, como uma bagunça desagradável para lidar com a semântica de divisão truncada (especialmente porque, em muitos processadores) , uma divisão por piso dividido por três poderia ser feita mais rapidamente do que uma truncada!) #Sim, não é nada importante por si só, seu único benefício é o açúcar sintático que facilita a digitação.
A razão pela qual está em C em primeiro lugar é apenas porque o PDP-11 que era a base para C, nos velhos tempos, tinha uma instrução especial para aumentar em 1. Naqueles dias, o uso dessa instrução era importante para obtenha mais velocidade do sistema, daí o recurso de idioma.
No entanto, acho que as pessoas gostam tanto do comando que reclamariam se não estivesse lá.
fonte
Essa é uma sintaxe idiomática em C para muitas situações (como o
for
loop que você citou); portanto, como outros já disseram, pode ajudar aqueles que fazem a transição para Java como uma nova linguagem e facilita a porta de código C pré-existente. Por esses motivos, inclusive foi uma decisão natural a ser tomada nos primeiros dias de Java para acelerar a adoção da nova linguagem. Faz menos sentido agora, porque o código mais compacto custa às custas dos programadores aprenderem sintaxe que não é estritamente necessária.Quem gosta, acha conveniente e natural. Ficar sem parece estranho. Usá-lo não ganha eficiência, é uma questão de legibilidade. Se você acha que seus programas são mais fáceis de ler e manter usando esses operadores, use-os.
O sentido original em C era mais do que apenas "adicionar 1" ou "subtrair 1". É muito mais do que apenas açúcar sintático ou pequenos ganhos de desempenho. O operador em C significa "incremento (ou decremento) para o próximo item". Se você tiver um ponteiro para algo maior que um byte e for para o próximo endereço como em
*pointer++
, o incremento real poderá ser de 4 ou 8 ou o que for necessário. O compilador faz o trabalho para você, acompanhando o tamanho dos itens de dados e pulando o número certo de bytes:Na minha máquina, isso adiciona 4 ao kpointer, não adiciona 1. Esta é uma ajuda real em C, evitando erros e salvando invocações espúrias de sizeof (). Não há aritmética de ponteiro equivalente em Java, portanto, isso não é uma consideração. Lá, é mais sobre o poder da expressão do que qualquer outra coisa.
fonte