Por que não há operadores de atribuição compostos para operadores lógicos (como ||, && etc)?

20

De acordo com ECMA-262, parte 11,13, seguinte é uma lista exaustiva dos operadores de atribuição compostos: *= /= %= += -= <<= >>= >>>= &= ^= |=.

De acordo com a parte 11.11, var c = a || bcolocará avalor em cse ToBoolean(a)for verdadeiro e colocará bvalor em ccaso contrário. Como tal, o OR lógico é frequentemente usado como operador de coalescência, por exemplo

function (options) {
    options = options || {};
}

Com freqüência suficiente, coalesce é usado para especificar o valor padrão para a variável, como foi mostrado acima: a = a || b.

Parece que o operador de atribuição composto ||=seria realmente útil, permitindo a escrever o código acima de uma forma mais curta e mais limpo: a ||= b. No entanto, não é ali (embora *=, +=e outros operadores de atribuição composto são).

A questão é, por quê?

penartur
fonte
2
Estou incrivelmente perplexo que o operador% = exista. Quem decidiu que era necessário? Alguns desses operadores parecem más decisões de design de linguagem.
Jonathan Rich
2
@ JonathanRich: por que não ter% =? Se você tiver algum desses operadores de atribuição, mais cedo ou mais tarde algum desenvolvedor (como penartur) se perguntará por que os operadores são "mais iguais" que outros.
Kevin cline #
4
@JonathanRich Crypto faz uso significativo do módulo. Furthemore, há uma ortogonalidade desejado com o resto da aritmética para operadores de atribuição aritméticos (Se alguém espera +=, *=, -=, /=, por que não faria %=o trabalho?).
4
@ JonathanRich: O operador é útil quando você tem algo circular e deseja normalizá-lo, por exemplo, angle %= 360ou vertexIndex %= numberOfVertices(para a lista de vértices de um polígono fechado).
Sebastian Negraszus

Respostas:

12

Uma razão possível é que os operadores lógicos &&e ||tenham um comportamento de "curto-circuito". O operando do lado direito &&e ||não é avaliado, a menos que seja necessário. Talvez por esse motivo, os designers de linguagem a ||= f()tenham decidido que o significado de uma expressão como não era óbvio e, portanto, esses operadores deveriam ficar de fora.

Kevin Cline
fonte
2
Sim. Por exemplo, muitas pessoas acreditam que isso a ||= bdeve ser interpretado como a = a || b, mas na verdade pode ser a || a = b(como no Ruby ). Eles podem ser diferentes se o levantador tiver efeito colateral. Escolher um pode ser ruim para os usuários do outro campo. Pessoalmente, gosto do a || a = bjeito (do jeito Ruby), mas não tenho certeza se todos estão felizes com isso.
Franklin Yu
8

A resposta geral a todas as perguntas sobre "por que esse recurso de idioma não foi implementado" é que a equipe que projetou o idioma decidiu que o benefício não superava o custo.

O custo pode assumir várias formas. Leva tempo e esforço para implementar um recurso de linguagem, mas também há o custo intrínseco da complexidade: o recurso torna o idioma mais complexo ou ambíguo, desproporcional ao seu benefício potencial?

O ||=operador hipotético faz algo fundamentalmente diferente dos outros operadores de atribuição composta. Enquanto os outros operadores são puramente matemáticos por natureza, este é diferente: ele substitui um valor por outro (no contexto que você descreveu).

Dada essa ambiguidade (o operador executa duas funções diferentes, dependendo do contexto), não é difícil perceber por que não foi incluído no idioma. Embora você afirme que mudar

function (options) {
    options = options || {};
}

para

function (options) {
    options ||= {};
}

executar coalescência nula é um recurso valioso, o benefício é muito menos claro para mim. Se ocorrer substituição de valor, parece lógico (e mais claro) ter ambos os valores no lado direito do sinal de igual, para fornecer uma indicação visual de que essa substituição pode ocorrer.

O C # seguiu um caminho diferente e usa um operador específico para coalescência nula.

Robert Harvey
fonte
1
Ao ler o código, o primeiro exemplo ali lê mais naturalmente - "opções iguais a opções ou nada" - comparado ao segundo - "opções ou igual a nada". Acho que este é apenas mais um motivo para não incluir o "ou é igual a" operador
Andy Hunt
Excelente abertura para sua resposta. E acho que o início da sua resposta pertence ao wiki da tag.
3
@AndyBursh A mesma lógica pode ser aplicada a qualquer operador de atribuição composta. "X é igual a X vezes 2" é mais natural em comparação com o "X vezes é igual a 2".
penartur
2
Observe que a digitação foo = foo || barexige que você digite fooduas vezes. Isso é complicado e também propenso a refatorar erros de digitação.
Phrogz
1
Acho que você não entendeu o significado de "matemático", talvez tenha ouvido falar em álgebra booleana. Concordo que coagir um não-booleano para usá-lo ||=como um operador coalescente nulo não é intuitivo e, na verdade, parece obtuso na forma de código. Onde isso se torna útil é quando você está tentando fazer cálculos booleanos. function fulfill(inValue) { if(resolved || rejected) return false; /* Do stuff here */ return true; } resolved ||= fulfill(value)
Joshperry
3

Você está certo que ||=é uma construção útil. Existe no Perl.

De fato, o Perl disponibiliza tudo isso :

**=    +=    *=    &=    <<=    &&=   -=    /=    
|=     >>=   ||=   .=    %=     ^=    //=   x=

Alguns deles são ótimos ( .=adiciona algo ao final de uma string), outros menos ( &&=acho que a variável seria configurada para o lado direito se ela e a variável forem verdadeiras. Mas por que você faria isso? ?)

O que está incluído em um idioma é realmente um recurso de sua filosofia de design.


fonte
3
stackoverflow.com/questions/12589467/… para o que &&=significa / faz.
Mat