operator from examples different bitwise language-agnostic bitwise-operators negation

language agnostic - from - ¿Algún idioma tiene un operador de cambio booleano único?



c++ operator (12)

Así que esta es más una pregunta teórica. C ++ y los lenguajes (in) basados ​​directamente 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 cambiar una expresión booleana siempre me encuentro escribiendo algo así como

a = !a;

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 cambio booleano único 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 (así que no hay 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 integrado y, de ser así, por qué decidieron no hacerlo.

(Nota: Sé que algunas personas opinan que la asignación no debería usar = y que ++ y += no son operadores útiles sino defectos de diseño; supongamos que estoy contento con ellos y nos centramos en por qué no se extenderían a los bools).


Activar el bit booleano

... eso me permitiría abreviar a = !a sin repetir la expresión para a ...

Este enfoque no es realmente un operador puro de "mutación invertida", pero cumple con los criterios anteriores; El lado derecho de la expresión no implica la variable en sí.

Cualquier idioma con una asignación XOR booleana (por ejemplo, ^= ) permitiría cambiar el valor actual de una variable, por ejemplo a , por medio de la asignación XOR a true :

// type of a is bool a ^= true; // if a was false, it is now true, // if a was true, it is now false

Como lo señala @cmaster en los comentarios a continuación, lo anterior asume que a es de tipo bool , y no, por ejemplo, un entero o un puntero. Si a es, de hecho, algo más (por ejemplo, algo que no es de tipo bool evaluando un valor "verdadero" o "falso", con una representación de bits que no es 0b1 o 0b0 , respectivamente), lo anterior no se cumple.

Para un ejemplo concreto, Java es un lenguaje en el que está bien definido y no está sujeto a conversiones silenciosas. Citando el comentario de @ Boann desde abajo:

En Java, ^ y ^= tienen un comportamiento definido explícitamente para booleanos y para enteros ( 15.22.2. Operadores lógicos booleanos & , ^ , y | ), donde ambos lados del operador deben ser booleanos, o ambos lados deben ser enteros. No hay conversión silenciosa entre esos tipos. Por lo tanto, no funcionará de forma silenciosa si a se declara como un entero, sino que da un error de compilación. Entonces a ^= true; Es seguro y está bien definido en Java.

Swift: toggle()

A partir de Swift 4.2, la siguiente propuesta de evolución ha sido aceptada e implementada:

Esto agrega una función nativa toggle() al tipo Bool en Swift.

toggle()

Alterna el valor de la variable booleana.

Declaración

mutating func toggle()

Discusión

Utilice este método para cambiar un valor booleano de true a false o de false a true .

var bools = [true, false] bools[0].toggle() // bools == [false, false]

Esto no es un operador, per se, pero permite un enfoque nativo de idioma para la activación booleana.


En pitón

Python admite dicha funcionalidad, si la variable tiene un tipo bool (que es Verdadero o Falso) con el operador exclusive or (^=) :

a = False a ^= True print(a) # --> True a ^= True print(a) # --> False


Disminuir un bool C99 tendrá el efecto deseado, al igual que aumentar o disminuir los tipos de bit admitidos en algunos dialectos de microcontroladores pequeños (que, según he observado, tratan los bits como campos de bits de un solo bit, por lo que todos los números pares se truncan a 0 y todos los números impares a 1). No recomendaría particularmente este uso, en parte porque no soy un gran fanático de la semántica de tipo bool [IMHO, el tipo debería haber especificado que un bool para el que se almacena cualquier valor distinto de 0 o 1 puede comportarse cuando se lee como si tuviera un valor entero no especificado (no necesariamente consistente); Si un programa está intentando almacenar un valor entero que no se sabe que es 0 o 1, ¡debería usarlo !! en él primero].


En Rust, puede crear su propio rasgo para extender los tipos que implementan el Not rasgo:

use std::ops::Not; use std::mem::replace; trait Flip { fn flip(&mut self); } impl<T> Flip for T where T: Not<Output = T> + Default, { fn flip(&mut self) { *self = replace(self, Default::default()).not(); } } #[test] fn it_works() { let mut b = true; b.flip(); assert_eq!(b, false); }

También puede usar ^= true como se sugiere, y en el caso de Rust, no hay ningún problema posible para hacer esto porque false no es un entero "disfrazado" como en C o C ++:

fn main() { let mut b = true; b ^= true; assert_eq!(b, false); let mut b = false; b ^= true; assert_eq!(b, true); }


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:

#include <iostream> namespace notstd { // define a flag type struct invert_flag { }; // make it available in all translation units at zero cost static constexpr auto invert = invert_flag{}; // for any T, (T << invert) ~= (T = !T) template<class T> constexpr T& operator<<(T& x, invert_flag) { x = !x; return x; } } int main() { // unleash Hell using notstd::invert; int a = 6; std::cout << a << std::endl; // let confusion reign amongst our hapless maintainers a << invert; std::cout << a << std::endl; a << invert; std::cout << a << std::endl; auto b = false; std::cout << b << std::endl; b << invert; std::cout << b << std::endl; }

Rendimiento esperado:

6 0 1 0 1


Esta pregunta es ciertamente interesante desde un punto de vista puramente teórico. Dejando de lado si un operador de conmutador booleano mutante unario o no sería útil, 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 te 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 siento seguro de decir que ningún idioma ha implementado este operador como una operación in situ de mutación estricta (corríjame si encuentra una). Entonces, lo siguiente sería ver si hay idiomas que te permitan construir uno. Lo que esto requeriría es dos cosas:

  1. Poder implementar operadores (unarios) con funciones.
  2. permitiendo que dichas funciones tengan argumentos de paso por referencia (para que puedan mutar sus argumentos directamente)

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. La oxidación solo permite la sobrecarga del operador para tipos personalizados. Casi se podría lograr esto en Scala , que le permite usar funciones con un nombre muy creativo y también omitir paréntesis, pero lamentablemente no hay paso por referencia. Fortran se acerca mucho porque permite operadores personalizados, pero específicamente les prohíbe tener parámetros de entrada (que están permitidos en funciones normales y subrutinas).

Sin embargo, hay al menos un idioma que marca todas las casillas necesarias: 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 . He aquí y

prefix operator ^ prefix func ^ (b: inout Bool) { b = !b } var foo = true print(foo) // true ^foo print(foo) // false


Mientras incluyamos el lenguaje ensamblador ...

ADELANTE

INVERT para un complemento bit a bit.

0= para un complemento lógico (verdadero / falso).


Supongo que no va a elegir un lenguaje basado únicamente en esto :-) En cualquier caso, puede hacer esto en C ++ con algo como:

inline void makenot(bool &b) { b = !b; }

Vea el siguiente programa completo por ejemplo:

#include <iostream> inline void makenot(bool &b) { b = !b; } inline void outBool(bool b) { std::cout << (b ? "true" : "false") << ''/n''; } int main() { bool this_dataSource_trackedObject_currentValue_booleanFlag = false; outBool(this_dataSource_trackedObject_currentValue_booleanFlag); makenot(this_dataSource_trackedObject_currentValue_booleanFlag); outBool(this_dataSource_trackedObject_currentValue_booleanFlag); makenot(this_dataSource_trackedObject_currentValue_booleanFlag); outBool(this_dataSource_trackedObject_currentValue_booleanFlag); }

Esto produce, como se esperaba:

false true false


Visual Basic.Net admite esto a través de un método de extensión.

Define el método de extensión así:

<Extension> Public Sub Flip(ByRef someBool As Boolean) someBool = Not someBool End Sub

Y luego llámalo así:

Dim someVariable As Boolean someVariable = True someVariable.Flip

Entonces, tu ejemplo original se vería algo así como:

me.DataSource.TrackedObject.CurrentValue.BooleanFlag.Flip


En C # :

boolean.variable.down.here ^= true;

El operador booleano ^ es XOR, y XORing con verdadero es lo mismo que invertir.