C'est donc plus une question théorique. C ++ et les langages (in) directement basés sur celui-ci (Java, C #, PHP) ont des opérateurs de raccourcis pour affecter le résultat de la plupart des opérateurs binaires au premier opérande, comme
a += 3; // for a = a + 3
a *= 3; // for a = a * 3;
a <<= 3; // for a = a << 3;
mais quand je veux basculer une expression booléenne, je me surprends toujours à écrire quelque chose comme
a = !a;
ce qui devient ennuyeux quand a
est une longue expression comme.
this.dataSource.trackedObject.currentValue.booleanFlag =
!this.dataSource.trackedObject.currentValue.booleanFlag;
(ouais, la loi de Demeter, je sais).
Je me demandais donc s'il existe un langage avec un opérateur de bascule booléen unaire qui me permettrait d'abréger a = !a
sans répéter l'expression pour a
, par exemple
!=a;
// or
a!!;
Supposons que notre langage ait un type booléen approprié (comme bool
en C ++) et qu'il a
soit de ce type (donc pas de style C int a = TRUE
).
Si vous pouvez trouver une source documentée, je serais également intéressé de savoir si, par exemple, les concepteurs C ++ ont envisagé d'ajouter un opérateur comme celui-ci lorsqu'il bool
est devenu un type intégré et si oui, pourquoi ils ont décidé de ne pas le faire.
(Note: Je sais que certaines personnes sont d'avis que la cession ne devrait pas utiliser
=
et que ++
et +=
ne sont pas opérateurs utiles , mais des défauts de conception, Assumons que je suis heureux avec eux et se concentrer sur la raison pour laquelle ils ne seraient pas étendre à bools).
la source
void Flip(bool& Flag) { Flag=!Flag; }
Le raccourcit votre expression longue.this.dataSource.trackedObject.currentValue.booleanFlag ^= 1;
*= -1
cependant, ce qui, pour une raison quelconque, je trouve plus intuitif que^= true
.Réponses:
Cette question est en effet intéressante d'un point de vue purement théorique. Mettant de côté la question de savoir si un opérateur de bascule booléen unaire et mutant serait utile, ou pourquoi de nombreuses langues ont choisi de ne pas en fournir, je me suis aventuré dans une quête pour voir s'il existe ou non.
TL; DR apparemment non, mais Swift vous permet d'en implémenter un. Si vous souhaitez seulement voir comment cela se fait, vous pouvez faire défiler vers le bas de cette réponse.
Après une recherche (rapide) sur les fonctionnalités de différentes langues, je me sentirais en sécurité pour dire qu'aucune langue n'a implémenté cet opérateur en tant qu'opération sur place à mutation stricte (corrigez-moi si vous en trouvez une). La prochaine chose à faire serait donc de voir s'il existe des langages qui vous permettent d'en créer un. Cela nécessiterait deux choses:
De nombreuses langues seront immédiatement exclues pour ne pas prendre en charge l'une ou l'autre de ces exigences ou les deux. Java for one n'autorise pas la surcharge d'opérateurs (ou d'opérateurs personnalisés) et de plus, tous les types primitifs sont passés par valeur. Go n'a aucun support pour la surcharge des opérateurs (sauf par des hacks ). Rust autorise uniquement la surcharge des opérateurs pour les types personnalisés. Vous pourriez presque y parvenir dans Scala , qui vous permet d'utiliser des fonctions nommées de manière très créative et d'omettre également les parenthèses, mais malheureusement, il n'y a pas de référence. Fortran est très proche en ce sens qu'il permet aux opérateurs personnalisés, mais leur interdit spécifiquement d'avoir des inout paramètres (qui sont autorisés dans les fonctions et sous-programmes normaux).
Il existe cependant au moins une langue qui coche toutes les cases nécessaires: Swift . Alors que certaines personnes se sont liées à la prochaine fonction membre .toggle () , vous pouvez également écrire votre propre opérateur, qui prend en effet en charge les arguments inout . Et voilà:
la source
Basculer le bit booléen
Cette approche n'est pas vraiment un pur opérateur de «retournement mutant», mais remplit vos critères ci-dessus; le côté droit de l'expression n'implique pas la variable elle-même.
Tout langage avec une affectation XOR booléenne (par exemple
^=
) permettrait de basculer la valeur actuelle d'une variable, par exemplea
, au moyen d'une affectation XOR àtrue
:Comme indiqué par @cmaster dans les commentaires ci-dessous, ce qui précède suppose qu'il
a
est de typebool
, et non par exemple un entier ou un pointeur. S'ila
s'agit en fait de quelque chose d'autre (par exemple quelque chose quibool
n'évalue pas à une valeur "véridique" ou "falsifiée", avec une représentation binaire qui n'est pas0b1
ou0b0
, respectivement), ce qui précède ne tient pas.Pour un exemple concret, Java est un langage dans lequel il est bien défini et ne fait l'objet d'aucune conversion silencieuse. Citant le commentaire de @ Boann ci-dessous:
Rapide:
toggle()
Depuis Swift 4.2, la proposition d'évolution suivante a été acceptée et mise en œuvre:
Cela ajoute une
toggle()
fonction native auBool
type dans Swift.Ce n'est pas un opérateur en soi, mais permet une approche native du langage pour le basculement booléen.
la source
En C ++, il est possible de commettre le péché cardinal de redéfinir le sens des opérateurs. Dans cet esprit, et un peu d'ADL, tout ce que nous devons faire pour déchaîner le chaos sur notre base d'utilisateurs est la suivante:
production attendue:
la source
operator<<
a fini par signifier «diffusé en streaming» en raison de son abus initial dans la STL. Cela ne signifiera pas naturellement «appliquer la fonction de transformation sur le RHS», ce qui est essentiellement ce à quoi je l'ai réaffecté ici.<<
y a un opérateur de décalage de bits, pas un opérateur de «flux sortant». Le problème avec votre redéfinition n'est pas qu'elle est incompatible avec les significations existantes de l'opérateur, mais plutôt qu'elle n'ajoute aucune valeur sur un simple appel de fonction.<<
semble être une mauvaise surcharge. Je ferais!invert= x;
;)Tant que nous incluons le langage d'assemblage ...
FORTH
INVERT
pour un complément au niveau du bit.0=
pour un complément logique (vrai / faux).la source
not
est un opérateur "bascule" :-)La décrémentation d'un C99
bool
aura l'effet désiré, tout comme l'incrémentation ou la décrémentation dubit
types pris en charge dans certains dialectes de minuscules microcontrôleurs (qui, d'après ce que j'ai observé, traitent les bits comme des champs de bits larges d'un seul bit, de sorte que tous les nombres pairs sont tronqués à 0 et tous nombres impairs à 1). Je ne recommanderais pas particulièrement une telle utilisation, en partie parce que je ne suis pas un grand fan de labool
sémantique de type [À mon humble avis, le type aurait dû spécifier que abool
auquel toute valeur autre que 0 ou 1 est stockée peut se comporter lorsqu'il est lu comme si il contient une valeur entière non spécifiée (pas nécessairement cohérente); si un programme essaie de stocker une valeur entière qui n'est pas connue pour être 0 ou 1, il doit l'utiliser!!
en premier].la source
bool
jusqu'à C ++ 17 .Langue d'assemblage
Voir https://www.tutorialspoint.com/assembly_programming/assembly_logical_instructions.htm
la source
; here edx would be 0xFFFFFFFE because a bitwise NOT 0x00000001 = 0xFFFFFFFE
if(x)
construction , il est tout à fait raisonnable d'autoriser 0 / -1 comme faux / vrai, comme pour les comparaisons SIMD ( felixcloutier.com/x86/PCMPEQB:PCMPEQW:PCMPEQD.html ). Mais vous avez raison de dire que cela casse si vous l'utilisez sur une autre valeur.Je suppose que vous n'allez pas choisir un langage basé uniquement sur ceci :-) Dans tous les cas, vous pouvez le faire en C ++ avec quelque chose comme:
Voir le programme complet suivant par exemple:
Cela produit, comme prévu:
la source
return b = !b
aussi? Quelqu'un qui litfoo = makenot(x) || y
ou simplement un simplefoo = makenot(bar)
peut supposer quemakenot
c'est une fonction pure et supposer qu'il n'y a pas d'effet secondaire. Enterrer un effet secondaire dans une expression plus large est probablement un mauvais style, et le seul avantage d'un type de retour non vide est de l'activer.template<typename T> T& invert(T& t) { t = !t; return t; }
, quel modèle sera converti vers / depuisbool
s'il est utilisé sur un non-bool
objet. IDK si c'est bon ou mauvais. Vraisemblablement bon.PostScript , étant un concaténative , orienté pile langage comme Forth, a une bascule unaire, non . L' opérateur not bascule la valeur en haut de la pile. Par exemple,
Voir le Manuel de référence du langage PostScript (pdf) , p. 458.
la source
Visual Basic.Net prend en charge cela via une méthode d'extension.
Définissez la méthode d'extension comme ceci:
Et puis appelez-le comme ceci:
Ainsi, votre exemple original ressemblerait à quelque chose comme:
la source
Flip()
:=
etNot
. Il est intéressant d'apprendre que dans le cas de l'appel,SomeInstance.SomeBoolean.Flip
cela fonctionne même s'ilSomeBoolean
s'agit d'une propriété, alors que le code C # équivalent ne se compilerait pas.Dans Rust, vous pouvez créer votre propre trait pour étendre les types qui implémentent le
Not
trait:Vous pouvez également utiliser
^= true
comme suggéré, et dans le cas de Rust, il n'y a pas de problème possible car cefalse
n'est pas un entier "déguisé" comme en C ou C ++:la source
En Python
Python prend en charge cette fonctionnalité, si la variable a un type booléen (qui est True ou False) avec l'
exclusive or (^=)
opérateur:la source
En C # :
L'opérateur booléen ^ est XOR et XORing avec true est identique à l'inversion.
la source