Quand est-il approprié d'utiliser un opérateur au niveau du bit dans une expression conditionnelle?

15

Tout d'abord, quelques antécédents: je suis professeur d'informatique en formation et j'essaie de présenter les opérateurs booléens de java à ma classe de 10e année. Mon enseignant-mentor a examiné une feuille de travail que j'avais préparée et a fait remarquer que je pouvais les laisser utiliser un seul & ou | pour désigner les opérateurs, car ils "font la même chose".

Je suis conscient de la différence entre & et &&.
& est un opérateur au niveau du bit destiné à être utilisé entre des entiers, pour effectuer un "twiddling de bits".
&& est un opérateur conditionnel destiné à être utilisé entre des valeurs booléennes.

Pour prouver que ces opérateurs ne "font pas toujours la même chose", j'ai cherché un exemple où l'utilisation du bit entre les valeurs booléennes conduirait à une erreur. J'ai trouvé cet exemple

boolean bitwise;
boolean conditional;
int i=10, j=12;
bitwise = (i<j) | ((i=3) > 5); // value of i after oper: 3
System.out.println(bitwise+ " "+ i);
i=10; 
conditional = (i<j) || (i=3) > 5 ;  // value of i after oper: 10
System.out.println(conditional+ " "+ i);
i=10; 
bitwise = (i>j) & (i=3) > 5;   // value of i after oper: 3
System.out.println(bitwise+ " "+ i);
i=10; 
conditional = (i>j) && (i=3) > 5;  // value of i after oper: 10
System.out.println(conditional+ " "+ i);

Cet exemple montre que si une valeur doit être modifiée par la seconde moitié de l'expression, cela entraînerait une différence entre les résultats, car bitwise est un opérateur impatient, tandis que le conditionnel se comporte comme un court-circuit (n'évalue pas la seconde moitié, si la première moitié est fausse dans le cas de && et vraie dans le cas de ||).

J'ai un problème avec cet exemple. Pourquoi voudriez-vous changer une valeur en même temps que vous faites une comparaison dessus? Cela ne semble pas être un moyen robuste de coder. J'ai toujours été opposé à faire plusieurs opérations sur une seule ligne dans mon code de production. Cela ressemble à quelque chose que ferait un "cowboy codeur" sans conscience quant à la maintenabilité de son code. Je sais que dans certains domaines, le code doit être aussi compact que possible, mais c'est certainement une mauvaise pratique en général?

Je peux expliquer mon choix d'encourager l'utilisation de && et || sur & et | car il s'agit d' une convention de codage acceptée en génie logiciel .

Mais quelqu'un pourrait-il me donner un meilleur exemple, même réel, d'utilisation d'un opérateur au niveau du bit dans une expression conditionnelle?

Deerasha
la source

Réponses:

16

il est approprié lorsque vous effectuez une opération de masquage

si ((a & b)> 0) {...}

où a et b sont des entiers

|| et | et && et & ne sont pas interchangeables

| et & n'apparaîtra presque jamais dans une expression conditionnelle par eux-mêmes (le point du lien que vous avez inclus est que de telles choses sont le plus souvent des erreurs)

EDIT: Ne discutez pas avec votre mentor; même si vous gagnez, vous perdez. Expliquez plutôt que vous ne voulez pas confondre les élèves en mélangeant des opérateurs logiques et des opérateurs au niveau du bit dans la même leçon. Vous pourriez expliquer que si i = 3 et j = 2 alors i & j = 2, alors que i && j est une erreur. Cependant, l'explication plus simple est que vous enseignez des opérateurs booléens (logiques), donc jeter des équivalents au niveau du cas spécial est une distraction par rapport au point principal de la leçon. Il n'est pas nécessaire de rendre le mentor «mauvais», ni de produire des contre-exemples. La leçon se concentre sur les opérateurs booléens, et non sur les opérateurs au niveau du bit.

En corollaire, lorsque vous commencez à enseigner des opérateurs au niveau du bit, il n'est pas nécessaire de montrer les cas particuliers où + et - produisent les mêmes résultats que & et |

Steven A. Lowe
la source
Le code ci-dessus n'est pas faux cependant, il peut être déroutant, mais en l'état, le code ne contient pas d'erreur, n'est-ce pas? Je suis d'accord que l'utilisation d'opérateurs au niveau du bit de cette manière n'est pas très lisible, je ne l'aimerais pas si je le voyais dans une revue de code, mais c'est du Java légal (et C # aussi, en ignorant le System.out.println).
Steve
Merci d'avoir répondu à @Steven A. Lowe. Vous avez dit "|| et | et && et & ne sont pas interchangeables" mais bitwise = !(true & true == false);et condition = !(true && true == false);tous les deux auront la valeur true, donc dans ce cas ils sont interchangeables? Syntaxiquement peut-être, puisque le code compile toujours. Je conviens qu'ils sont utilisés pour différentes choses sémantiquement, comme je l'ai mentionné au paragraphe 2. Vous dites cela! et & "n'apparaissent presque jamais dans un conditionnel". Je cherche ces cas "presque jamais" et je me demande s'ils existent légitimement.
Deerasha
@Deerasha: || et && ne fonctionne que sur les booléens. & et | opérer sur des entiers et des booléens - il est inutile d'utiliser des opérateurs au niveau du bit (destinés à fonctionner sur plusieurs bits ) pour manipuler des booléens, et le faire avec abandon peut entraîner une confusion du code et des comportements inattendus (c'est-à-dire si vous utilisez accidentellement un entier au lieu d'un booléen, les opérateurs au niveau du bit ne se plaindront pas)
Steven A. Lowe
Oui @Steve Haigh, le compilateur ne le rejette pas, mais ce n'est pas la bonne façon de les utiliser, à en juger par la norme de codage publiée à laquelle je suis lié. Puis-je me reposer confortablement sur son rejet parce qu'il n'est pas conforme à une norme de codage, ou est-ce que java peut peut-être indiquer qu'il s'agit d'une mauvaise utilisation?
Deerasha
2
@Steven A. Lowe: si i = 3 et j = 2 alors i & j = 2, alors que i && j est une erreur C'est génial! C'est simple et ça fait le point. Au niveau de la 10e année, c'est également une erreur probable, car ils s'habituent toujours au type booléen et à quoi les opérateurs s'appliqueraient. Merci beaucoup! Un excellent conseil pour ne pas discuter avec mon mentor non plus.
Deerasha
12

Les opérateurs non binaires &&et ||sont des opérateurs de court-circuit. En d'autres termes, avec &&, si le LHS est faux, le RHS ne sera jamais évalué; avec ||si le LHS est vrai, l'ERS ne sera jamais évaluée. D'un autre côté, les opérateurs au niveau du bit &et ne |sont pas en court-circuit, et évalueront toujours à la fois le LHS et le RHS. Sinon, ils sont équivalents dans une ifdéclaration.

La seule fois où je peux voir la valeur de l'utilisation des opérateurs non-court-circuit est si le RHS a une sorte d'effet secondaire souhaitable que vous souhaitez voir se produire dans tous les cas. Je ne peux pas penser à un exemple précis où vous voudriez cela, et je ne pense pas que ce soit une bonne pratique, mais c'est la différence.

Jonathan
la source
1
+1. Exactement à droite, lorsque l'on compare les booléens au niveau du bit et les opérateurs logiques retournent toujours le même résultat, mais (en Java et C # au moins), seuls les opérateurs logiques court-circuitent.
Steve
Merci d'avoir répondu. Votre paragraphe 1 était ce que j'essayais de comprendre dans mon paragraphe 4, en déclarant que le bit à bit est un opérateur avide tandis que le conditionnel se comporte comme un court-circuit . Votre paragraphe 2 est la préoccupation que j'ai décrite dans mon paragraphe 5. Je suis donc conscient de la différence, mais je recherche cet exemple précis auquel ni vous ni moi ne pouvons penser.
Deerasha
7

La réponse philosophique générale est que l'utilisation d'opérateurs au niveau du bit pour les opérateurs booléens est atypique et rend le code plus difficile à lire. En pratique (pour le code en production), un code plus lisible est plus facile à maintenir et donc plus souhaitable.

Pour une utilisation réelle du besoin d'opérateurs de court-circuit, voir des cas tels que:

if (args.length > 0 && args[0] == 'test') ....

if (b != NULL && b.some_function()) ...

if (b == NULL || b.some_function()) ...

Ce type d'opérations apparaît fréquemment dans le code du monde réel.

Kathy Van Stone
la source
Tfa. Comment expliquer à mes 15 ans que 1 &est «plus difficile à lire» que 2? Je n'ai pas d'exemple dans lequel les 2 opérateurs ne fonctionnent pas de la même manière pour les opérandes booléens. Je suis d'accord sur votre point concernant le code plus lisible et plus facile à maintenir. Je veux les encourager à écrire du beau code. Mais avoir des preuves dans mon sac d'outils serait plus convaincant que «parce que je l'ai dit». Je l'ai indiqué comme norme à ce lien, et je devrai peut-être m'en remettre à cela uniquement si je ne reçois pas l'exemple que je recherche. Comme je l'ai demandé à @Steve Haigh: Java devrait-il indiquer cela comme une mauvaise utilisation?
Deerasha
@Deerasha Je pensais plus à une dispute avec votre mentor. Pour la classe, n'essayez même pas de leur dire que vous pouvez utiliser des opérateurs au niveau du bit pour des conditions logiques.
Kathy Van Stone
4

Vous utiliserez des opérateurs au niveau du bit si vous comparez les énumérations Bitmask. Par exemple, vous disposez d'une énumération d'états et d'un objet qui peut se trouver dans plusieurs de ces états. Dans ce cas, vous devrez faire un bit à bit ou assigner plus d'un état à votre objet.

par exemple state = CONNECTED | IN_PROGRESSCONNECTED could be 0x00000001etIN_PROGRESS 0x00000010

Pour plus d'informations, consultez la documentation des énumérations d'indicateurs.

pwny
la source
Grâce à vous, j'ai appris une application d'opérateurs bit à bit que je ne connaissais pas auparavant! Mais dans cet exemple, seul l'opérateur au niveau du bit s'applique. Je cherche un morceau de code bien écrit où l'utilisation du bit plutôt que du conditionnel conduirait à une compilation, mais une sortie incorrecte. Autrement dit, si un tel extrait de code existe.
Deerasha
Je ne pense pas que cela puisse se produire en Java car je crois que l'appeler | ou & opérateurs sur des valeurs qui ne peuvent pas être binaires et'd ou ou'd effectue simplement une logique | ou &. Je ne me souviens pas si c'est le cas en Java, mais sachez que c'est en C # MSDN: "Les opérateurs binaires | sont prédéfinis pour les types intégraux et booléens. Pour les types intégraux, | calcule le bit à bit OU de ses opérandes. Pour bool operands, | calcule le OU logique de ses opérandes "
pwny
Après quelques recherches supplémentaires, j'ai découvert que la seule différence entre | et || et & et && pour les opérandes booléens en Java est le comportement de court-circuit, donc le scénario que vous décrivez n'est pas vraiment possible.
pwny
0

un exemple plus simple de tort:

int condA=1, condB=2;

if (condA!=0 && condB!=0) {
    // correct!
}
if ((condA & condB)!=0) {
    // never executed
}

ici, vous avez deux conditions, les deux sont non nulles; mais le bit à bit& résultat au niveau est nul.

Javier
la source
@Javier: Merci d'avoir répondu, mais je suis un peu confus. Je travaille en java et ce code ne se compile pas. (condA && condB)des erreurs, car le && ne fonctionne pas pendant 2 ints, seulement 2 booléens. (condA & condB)bien que correct, évalue à un int et en java, nous ne pouvons pas le dire if(int), il se trompe aussi. Vous êtes le premier à comprendre ce que je recherche cependant - exactement cet exemple de mal .
Deerasha
n'ont pas utilisé Java depuis longtemps ... essayez (Boolean(condA) && Boolean(condB)) (je pense que Boolean(x)c'est truepour des entiers non nuls, non?)
Javier
Nope @Javier: Impossible de convertir l'int en booléen.
Deerasha
qu'en est-il ((condA!=0) && (condB!=0))?
Javier
@Javier oui, il compile, mais le "tort" n'est plus illustré if (((condA!=0) && (condB!=0))) { System.out.println("correct"); } if (((condA!=0) & (condB!=0))) { System.out.println("never executed?"); }exécute les deux instructions d'impression.
Deerasha