Portanto, essa é mais uma questão teórica. C ++ e linguagens (in) diretamente baseadas nele (Java, C #, PHP) possuem operadores de atalho para atribuir o resultado da maioria dos operadores binários ao primeiro operando, como
a += 3; // for a = a + 3
a *= 3; // for a = a * 3;
a <<= 3; // for a = a << 3;
mas quando quero alternar uma expressão booleana, sempre me pego escrevendo algo como
a = !a;
o que fica irritante quando a
é uma expressão longa como.
this.dataSource.trackedObject.currentValue.booleanFlag =
!this.dataSource.trackedObject.currentValue.booleanFlag;
(sim, a Lei de Demeter, eu sei).
Então, eu estava pensando, existe algum idioma com um operador de alternância booleano unário que me permita abreviar a = !a
sem repetir a expressão a
, por exemplo
!=a;
// or
a!!;
Vamos supor que nossa linguagem tenha um tipo booleano adequado (como bool
em C ++) e esse a
seja (sem estilo C int a = TRUE
).
Se você pode encontrar uma fonte documentada, eu também estaria interessado em saber se, por exemplo, os designers de C ++ consideraram adicionar um operador como esse quando bool
se tornou um tipo interno e, se sim, por que decidiram contra.
(Nota: Eu sei que algumas pessoas são da opinião de que a atribuição não deve usar
=
e que ++
e +=
não são operadores útil, mas falhas de projeto, vamos apenas supor que eu estou feliz com eles e foco em por que eles não se estenderia até bools).
fonte
void Flip(bool& Flag) { Flag=!Flag; }
Encurta sua longa expressão.this.dataSource.trackedObject.currentValue.booleanFlag ^= 1;
*= -1
, porém, que por algum motivo eu acho mais intuitivo do que^= true
.Respostas:
Esta questão é realmente interessante do ponto de vista puramente teórico. Deixando de lado se um operador booleano alternador unário ou mutante seria útil ou por que muitos idiomas optaram por não fornecer um, aventurei-me em uma missão para ver se ele realmente existe ou não.
TL; DR aparentemente não, mas Swift permite implementar um. Se você quiser apenas ver como isso é feito, role para a parte inferior desta resposta.
Após uma pesquisa (rápida) em recursos de vários idiomas, eu me sentiria seguro em dizer que nenhum idioma implementou esse operador como uma operação no local rigorosa de mutação (corrija-me se encontrar um). Portanto, o próximo passo seria verificar se existem idiomas que permitem a criação de um. O que isso exigiria é duas coisas:
Muitos idiomas serão descartados imediatamente por não suportar um ou ambos os requisitos. O Java for one não permite sobrecarga do operador (ou operadores customizados) e, além disso, todos os tipos primitivos são passados por valor. O Go não oferece suporte à sobrecarga do operador (exceto por hacks ). A ferrugem apenas permite sobrecarga do operador para tipos personalizados. Você quase conseguiu isso no Scala , que permite usar funções nomeadas de maneira muito criativa e também omitir parênteses, mas, infelizmente, não há passagem por referência. O Fortran fica muito próximo, pois permite operadores personalizados, mas proíbe-os especificamente de terem acesso parâmetros (permitidos em funções e sub-rotinas normais).
No entanto, há pelo menos um idioma que marca todas as caixas necessárias: Swift . Embora algumas pessoas tenham se vinculado à próxima função de membro .toggle () , você também pode escrever seu próprio operador, o que realmente suporta argumentos inout . Eis e eis que:
fonte
Alternando o bit booleano
Essa abordagem não é realmente um operador "flip mutante" puro, mas atende aos seus critérios acima; o lado direito da expressão não envolve a própria variável.
Qualquer idioma com uma atribuição XOR booleana (por exemplo
^=
) permitiria inverter o valor atual de uma variável, digamosa
, por meio da atribuição XOR paratrue
:Conforme apontado por @cmaster nos comentários abaixo, o acima pressupõe que
a
é do tipobool
e não, por exemplo, um número inteiro ou um ponteiro. Sea
é de fato outra coisa (por exemplo, algo que nãobool
avalia um valor "verdade" ou "falsidade", com uma representação de bits que não é0b1
ou0b0
, respectivamente), o acima não se aplica.Para um exemplo concreto, Java é uma linguagem em que isso é bem definido e não está sujeito a nenhuma conversão silenciosa. Citando o comentário de @ Boann abaixo:
Rápido:
toggle()
A partir do Swift 4.2, a seguinte proposta de evolução foi aceita e implementada:
Isso adiciona uma
toggle()
função nativa aoBool
tipo no Swift.Este não é um operador, por si só, mas permite uma abordagem nativa do idioma para alternância booleana.
fonte
Em C ++, é possível comprometer o Cardinal Sin de redefinir o significado dos operadores. Com isso em mente e um pouco de ADL, tudo o que precisamos fazer para liberar o caos em nossa base de usuários é o seguinte:
resultado esperado:
fonte
operator<<
passou a significar 'transmitido' por causa de seu abuso original no STL. Naturalmente, isso não significa 'aplicar a função de transformação no RHS', que é essencialmente o que eu propus para ele aqui.<<
é um operador de troca de bits, não um operador de "fluxo contínuo". O problema com sua redefinição não é inconsistente com os significados existentes do operador, mas sim que não agrega valor a uma simples chamada de função.<<
parece uma sobrecarga ruim. Eu faria!invert= x;
;)Contanto que incluamos linguagem assembly ...
ADIANTE
INVERT
para um complemento bit a bit.0=
para um complemento lógico (verdadeiro / falso).fonte
not
é um operador "toggle" :-)Decrementar um C99
bool
terá o efeito desejado, assim como aumentar ou diminuir osbit
tipos suportados em alguns dialetos de microcontroladores minúsculos (que pelo que observei tratam bits como campos de bits largos de um bit, para que todos os números pares sejam truncados para 0 e todos números ímpares para 1). Eu particularmente não recomendaria esse uso, em parte porque não sou um grande fã dobool
tipo semântica [IMHO, o tipo deveria ter especificado que umbool
para o qual qualquer valor diferente de 0 ou 1 é armazenado pode se comportar quando lido como se ele possui um valor inteiro não especificado (não necessariamente consistente); se um programa está tentando armazenar um valor inteiro que não é conhecido como 0 ou 1, ele deve ser usado!!
primeiro].fonte
bool
até o C ++ 17 .Linguagem Assembly
Consulte https://www.tutorialspoint.com/assembly_programming/assembly_logical_instructions.htm
fonte
; here edx would be 0xFFFFFFFE because a bitwise NOT 0x00000001 = 0xFFFFFFFE
if(x)
construção , é totalmente razoável permitir 0 / -1 como falso / verdadeiro, como nas comparações SIMD ( felixcloutier.com/x86/PCMPEQB:PCMPEQW:PCMPEQD.html ). Mas você está certo que isso quebra se você o usar em qualquer outro valor.Suponho que você não escolherá uma linguagem baseada apenas nisso :-) De qualquer forma, você pode fazer isso em C ++ com algo como:
Veja o seguinte programa completo, por exemplo:
Isso gera, conforme o esperado:
fonte
return b = !b
também? Alguém lendofoo = makenot(x) || y
ou apenas um simplesfoo = makenot(bar)
pode assumir que essamakenot
é uma função pura e assumir que não houve efeito colateral. Enterrar um efeito colateral dentro de uma expressão maior provavelmente é um estilo ruim, e o único benefício de um tipo de retorno não nulo é permitir isso.template<typename T> T& invert(T& t) { t = !t; return t; }
que o modelo que será convertido para / debool
se for usado em um não-bool
objeto. IDK se isso é bom ou ruim. Presumivelmente bom.PostScript , sendo um concatenativa , orientada a pilha de linguagem como Forth, tem uma alternância unário, não . O operador not alterna o valor no topo da pilha. Por exemplo,
Consulte o Manual de referência da linguagem PostScript (pdf) , p. 458
fonte
O Visual Basic.Net suporta isso por meio de um método de extensão.
Defina o método de extensão da seguinte maneira:
E então chame assim:
Portanto, seu exemplo original seria algo como:
fonte
Flip()
:=
eNot
. É interessante saber que, no caso de chamarSomeInstance.SomeBoolean.Flip
, funciona mesmo queSomeBoolean
seja uma propriedade, enquanto o código C # equivalente não seria compilado.No Rust, você pode criar sua própria característica para estender os tipos que implementam a
Not
característica:Você também pode usar
^= true
como sugerido e, no caso de Rust, não há problema possível para fazer isso porquefalse
não é um número inteiro "disfarçado", como em C ou C ++:fonte
Em Python
O Python suporta essa funcionalidade, se a variável tiver o tipo bool (que é True ou False) com o
exclusive or (^=)
operador:fonte
Em c # :
O operador booleano ^ é XOR e XOR com true é o mesmo que inverter.
fonte