Entonces esta es más una pregunta teórica. C ++ y los lenguajes (in) directamente basados en él (Java, C #, PHP) tienen operadores de acceso directo para asignar el resultado de la mayoría de los operadores binarios al primer operando, como
a += 3; // for a = a + 3
a *= 3; // for a = a * 3;
a <<= 3; // for a = a << 3;
pero cuando quiero alternar una expresión booleana siempre me encuentro escribiendo algo como
a = !a;
lo que se vuelve molesto cuando a
es una expresión larga como.
this.dataSource.trackedObject.currentValue.booleanFlag =
!this.dataSource.trackedObject.currentValue.booleanFlag;
(Sí, la Ley de Demeter, lo sé).
Así que me preguntaba, ¿hay algún lenguaje con un operador de alternancia booleano unario que me permita abreviar a = !a
sin repetir la expresión para a
, por ejemplo
!=a;
// or
a!!;
Supongamos que nuestro lenguaje tiene un tipo booleano adecuado (como bool
en C ++) y que a
es de ese tipo (por lo que no tiene estilo C int a = TRUE
).
Si puede encontrar una fuente documentada, también me interesaría saber si, por ejemplo, los diseñadores de C ++ han considerado agregar un operador como ese cuando bool
convirtió en un tipo incorporado y, de ser así, por qué decidieron no hacerlo.
(Nota: Sé que algunas personas son de la opinión de que la asignación no se debe usar
=
y que ++
y +=
no son útiles, pero los operadores de defectos de diseño, vamos a asumir que estoy feliz con ellos y se centran en por qué no se extenderían a Bools).
fuente
void Flip(bool& Flag) { Flag=!Flag; }
Acorta tu expresión larga.this.dataSource.trackedObject.currentValue.booleanFlag ^= 1;
*= -1
, sin embargo, que por alguna razón me parece más intuitivo que^= true
.Respuestas:
Esta pregunta es realmente interesante desde un punto de vista puramente teórico. Dejando a un lado si sería útil o no un operador de palanca booleano mutante o unario, o por qué muchos idiomas han optado por no proporcionar uno, me aventuré en una búsqueda para ver si realmente existe o no.
TL; DR aparentemente no, pero Swift le permite implementar uno. Si solo desea ver cómo se hace, puede desplazarse hasta el final de esta respuesta.
Después de una búsqueda (rápida) de las características de varios idiomas, me sentiría seguro al decir que ningún idioma ha implementado este operador como una operación in situ mutante estricta (corríjame si encuentra uno). Entonces, lo siguiente sería ver si hay idiomas que le permitan construir uno. Lo que esto requeriría es dos cosas:
Muchos idiomas se descartarán inmediatamente por no admitir ninguno de estos requisitos o ambos. Java for one no permite la sobrecarga de operadores (u operadores personalizados) y, además, todos los tipos primitivos se pasan por valor. Go no tiene soporte para la sobrecarga del operador (excepto por hacks ) en absoluto. Rust solo permite la sobrecarga del operador para tipos personalizados. Casi podría lograr esto en Scala , que le permite usar funciones con nombres muy creativos y también omitir paréntesis, pero lamentablemente no hay paso por referencia. Fortran se acerca mucho, ya que permite operadores personalizados, pero específicamente les prohíbe tener inout parámetros (que están permitidos en funciones normales y subrutinas).
Sin embargo, hay al menos un idioma que cumple todos los requisitos: Swift . Si bien algunas personas se han vinculado a la próxima función miembro .toggle () , también puede escribir su propio operador, que de hecho admite argumentos inout . Lo y he aquí:
fuente
Alternar el bit booleano
Este enfoque no es realmente un operador puro de "cambio mutante", pero cumple con los criterios anteriores; el lado derecho de la expresión no involucra la variable en sí.
Cualquier lenguaje con una asignación XOR booleana (por ejemplo
^=
) permitiría cambiar el valor actual de una variable, por ejemploa
, mediante la asignación XOR atrue
:Como señaló @cmaster en los comentarios a continuación, lo anterior supone que
a
es de tipobool
y no, por ejemplo, un número entero o un puntero. Si,a
de hecho, es otra cosa (por ejemplo, algo que no sebool
evalúa como un valor "verdadero" o "falso", con una representación de bits que no es0b1
o0b0
, respectivamente), lo anterior no se cumple.Para un ejemplo concreto, Java es un lenguaje donde está bien definido y no está sujeto a ninguna conversión silenciosa. Citando el comentario de @ Boann a continuación:
Rápido:
toggle()
A partir de Swift 4.2, la siguiente propuesta de evolución ha sido aceptada e implementada:
Esto agrega una
toggle()
función nativa alBool
tipo en Swift.Este no es un operador, per se, pero permite un enfoque nativo de lenguaje para alternar booleano.
fuente
En C ++ es posible cometer el pecado cardinal de redefinir el significado de los operadores. Con esto en mente, y un poco de ADL, todo lo que tenemos que hacer para desatar el caos en nuestra base de usuarios es esto:
Rendimiento esperado:
fuente
operator<<
ha llegado a significar 'transmitido' debido a su abuso original en el STL. Naturalmente, no significará 'aplicar la función de transformación en el RHS', que es esencialmente para lo que la he reubicado aquí.<<
es un operador de desplazamiento de bits, no un operador de "transmisión". El problema con su redefinición no es que sea inconsistente con los significados existentes del operador, sino que no agrega ningún valor sobre una simple llamada de función.<<
Parece una mala sobrecarga. Lo haría!invert= x;
;)Siempre que incluyamos lenguaje ensamblador ...
ADELANTE
INVERT
para un complemento bit a bit.0=
para un complemento lógico (verdadero / falso).fuente
not
es un operador "alternar" :-)Disminuir un C99
bool
tendrá el efecto deseado, al igual que aumentar o disminuir losbit
tipos admitidos en algunos dialectos de microcontroladores pequeños (que por lo que he observado tratan los bits como campos de bits anchos de un solo bit, por lo que todos los números pares se truncan a 0 y todos números impares a 1). En particular, no recomendaría tal uso, en parte porque no soy un gran admirador de labool
semántica de tipos [En mi humilde opinión, el tipo debería haber especificado que unbool
comportamiento al que se almacena cualquier valor distinto de 0 o 1 puede comportarse cuando se lee como si tiene un valor entero no especificado (no necesariamente consistente); si un programa está tratando de almacenar un valor entero que no se sabe que es 0 o 1, debería usarlo!!
primero].fuente
bool
hasta C ++ 17 .Lenguaje ensamblador
Ver https://www.tutorialspoint.com/assembly_programming/assembly_logical_instructions.htm
fuente
; here edx would be 0xFFFFFFFE because a bitwise NOT 0x00000001 = 0xFFFFFFFE
if(x)
construcción , es totalmente razonable permitir 0 / -1 como falso / verdadero, como para comparar SIMD ( felixcloutier.com/x86/PCMPEQB:PCMPEQW:PCMPEQD.html ). Pero tienes razón en que esto se rompe si lo usas en cualquier otro valor.Supongo que no va a elegir un lenguaje basado únicamente en esto :-) En cualquier caso, puede hacer esto en C ++ con algo como:
Vea el siguiente programa completo, por ejemplo:
Esto produce, como se esperaba:
fuente
return b = !b
también? Alguien leyendofoo = makenot(x) || y
o simplemente un simplefoo = makenot(bar)
podría asumir quemakenot
era una función pura, y asumir que no había ningún efecto secundario. Enterrar un efecto secundario dentro de una expresión más grande es probablemente un mal estilo, y el único beneficio de un tipo de retorno no nulo es habilitarlo.template<typename T> T& invert(T& t) { t = !t; return t; }
que las plantillas se convertirán a / desdebool
si se usan en unbool
objeto no . IDK si eso es bueno o malo. Presumiblemente bueno.PostScript , al ser una concatenación , orientado a pila idioma como el Forth, tiene un conmutador unario, no . El operador no alterna el valor en la parte superior de la pila. Por ejemplo,
Consulte el Manual de referencia del lenguaje PostScript (pdf) , pág. 458.
fuente
Visual Basic.Net admite esto mediante un método de extensión.
Defina el método de extensión así:
Y luego llámalo así:
Entonces, su ejemplo original se vería así:
fuente
Flip()
:=
yNot
. Es interesante saber que en el caso de llamarSomeInstance.SomeBoolean.Flip
funciona incluso siSomeBoolean
es una propiedad, mientras que el código C # equivalente no se compilaría.En Rust, puede crear su propio rasgo para extender los tipos que implementan el
Not
rasgo:También puedes usar
^= true
como se sugiere, y en el caso de Rust, no hay problema posible para hacer esto porquefalse
no es un número entero "disfrazado" como en C o C ++:fuente
En python
Python admite dicha funcionalidad, si la variable tiene tipo bool (que es Verdadero o Falso) con el
exclusive or (^=)
operador:fuente
En C # :
El operador booleano ^ es XOR, y XORing con verdadero es lo mismo que invertir.
fuente