Pourquoi est x == (x = y) pas la même chose que (x = y) == x?

Considérons l'exemple suivant:

class Quirky {
    public static void main(String[] args) {
        int x = 1;
        int y = 3;

        System.out.println(x == (x = y)); //false
        x = 1; //reset
        System.out.println((x = y) == x); //true
     }
}

Je ne sais pas si il y a un élément dans le Langage Java Spécification qui dicte le chargement de la valeur précédente de la variable pour la comparaison avec le côté droit (x = y) qui, par l'ordre implicite par des crochets, doit être calculé en premier.

Pourquoi la première expression à évaluer à false, mais la seconde d'évaluer à true? Je me serais attendu à (x = y) être évaluées en premier, puis les comparer x avec lui-même (3) et retour true.


Cette question est différente de l'ordre d'évaluation des sous-expressions dans une expression de Java dans ce x est certainement pas un "sous-expression' ici. Il doit être chargé pour la comparaison plutôt que d'être "évalué'. La question est de Java spécifiques et l'expression x == (x = y), contrairement à farfelue impossible constructions communément conçu pour les délicates questions de l'entrevue, venaient de un projet réel. C'était censé être une ligne de remplacement pour les comparer et de les remplacer idiome

int oldX = x;
x = y;
return oldX == y;

qui, en étant encore plus simple que x86 CMPXCHG d'instruction, s'est mérité une expression plus courte en Java.

  • Le côté gauche est toujours évalué avant le côté droit. Les crochets de ne pas faire une différence pour qu'.
  • Le terme évaluation est, à mon avis, inapplicable ici parce que x n'a pas besoin d'être évaluées, il vient d'être chargée à partir de la mémoire.
  • L'évaluation de l'expression x = y est certainement pertinente, et provoque un effet secondaire qui x est définie à la valeur de y.
  • Assurez-vous. Je le savais, et c'était l'idée principale qui m'a conduit à quickReplaceAndCompare().
  • Faire vous-même et vos coéquipiers une faveur et ne mélange pas l'état de la mutation dans la même ligne que l'examen d'état. Faire considérablement réduit la lisibilité de votre code. (Il y a des cas où c'est absolument nécessaire en raison de l'atomicité des exigences, mais les fonctions de ceux qui existent déjà et leur but serait reconnu instantanément.)
  • Pour un exemple de la frustration "raccourcis", comme cela peut causer, il m'a pris la meilleure partie de une minute pour traiter de ce bien suffisant pour voir ce que ces sont en train de faire. Je sais aussi que C++, et les règles sont différentes en C++ qu'ils sont ici en Java. En fait, en C++, c'est un comportement indéfini, il jette toutes sortes d'mentale des drapeaux rouges pour moi, le ralentissement de moi vers le bas plus que ce qu'ils devraient probablement. J'ai probablement lu par replaceAndCompare 100 fois plus rapide que je n'ai quickReplaceAndCompare.
  • La vraie question est de savoir pourquoi vous voulez écrire du code comme ceci.
  • Ne jamais écrire un tel code en production.
  • Une autre priorité de la question: Quelles sont les règles pour l'ordre d'évaluation en Java?
  • Off: si c'était de la C, il serait à l'évidence un cas d'UB, sens le compilateur peut générer quelque chose de lui.
  • Quelqu'un m'a dit une fois que toutes les expressions booléennes ont trois valeurs possibles: True, False et "putain de Stupide".
  • Ne des constructions telles que celles de l'OP effectivement donner aucune garantie de l'atomicité?
  • La clé de votre question, c'est votre croyance fausse que les parenthèses implique ordre d'évaluation. C'est une croyance commune en raison de la façon dont on enseigne les mathématiques à l'école primaire et parce que certains débutants livres de programmation de toujours se tromper, mais c'est une fausse croyance. C'est plutôt une question fréquente. Vous pouvez bénéficier de la lecture de mes articles sur le sujet, ils sont sur le C#, mais ils s'appliquent à Java: ericlippert.com/2008/05/23/precedence-vs-associativity-vs-order ericlippert.com/2009/08/10/precedence-vs-order-redux
  • Non, je fais référence à des choses comme ceci. Les opérations atomiques sont explicites, c'est pourquoi ils sont instantanément reconnus. Désolé de ne pas être plus clair.
  • En particulier, pensez à quelque chose comme x() * (y() + z()) L'ordre des appels de fonction est pas y puis z puis x parce que "les parenthèses venir en premier". Les parenthèses de déterminer la sous-expression de frontières, pas de l'ordre d'évaluation. Le * a deux sous-expressions: x() et (y() + z()). Celui de gauche, x(), qui se produit en premier. Puis celui de droite qui se passe: y() est appelé, z() est appelé, et ils sont additionnés. Ensuite, la multiplication a lieu. Ainsi, le + qui se passe avant le *, comme il se doit, mais les opérandes en plus de ne pas arriver en premier.
  • Je pense qu'une partie du problème est que les enseignants de mathématiques se réfèrent à des règles de priorité des opérateurs comme “l'ordre des opérations”, et le mot “ordre” voyage les gens.
  • "x est certainement pas un" sous-expression "ici" - Il est vraiment. Pourquoi pensez-vous que le "chargement" de la valeur d'une variable n'est pas à l'exemple de "l'évaluation"? L'évaluation donne une valeur, pas une variable ou d'un emplacement mémoire.
  • L'affiche originale est, comme vous le notez, un peu confus. Cependant votre relevé que l'évaluation donne une valeur, pas une variable, n'est pas étayée par des preuves. Considérons par exemple array()[index()] = value(); La sémantique de Java sont ce que nous appelons la array(), puis index(), puis value(); l'ensemble de ces valeurs. Mais il faut alors vérifier si le tableau de référence est valide et de le jeter si elle n'est pas, et de vérifier ensuite si l'index est valide, et de le jeter si elle ne l'est pas. Mais absolument la sous-expression à gauche de l'affectation n'est pas une valeur. Il s'agit d'une variable.
  • Votre déclaration est directement contredite par la spécification de Java. Les langages tels que C la distinction entre "lvalues" et "rvalues"; un "lvalue" est la "valeur", produit par l'évaluation de la partie gauche d'une affectation. C'est critiquée à juste titre comme étant source de confusion; Java et C#) d'éviter ce problème en évitant cette notion que assignables choses sont des "valeurs", et au lieu de les appeler ce qu'ils sont: des variables. Les spécifications de Java pour l'affectation le rend très clair: "tout d'Abord, la gauche opérande est évaluée pour produire une variable..."
  • n'est certainement pas un "sous-expression "ici" - sur la base de quels critères pensez-vous cela?
  • Parce que l'expression implique opérateur(s).
  • Que l'énoncé est faux; une expression qui n'a pas besoin d'impliquer tout opérateur. Encore une fois, vous faites très bien de lire le cahier des charges, parce que vous avez un grand nombre de fausses croyances. Détromper vous d'eux!
  • Afin de voir à partir de la spécification (docs.oracle.com/javase/specs/jls/se11/html/jls-15.html), qu'il y a des expressions sans opérateurs, vous pouvez suivre la syntaxe de la Expression terminal par le biais de plusieurs niveaux, par le biais de PostFixExpression et ExpressionName. Ou regarder MethodInvocation, dont ArgumentList se compose de comma-separated expressions. Si toutes les expressions ont été nécessaires pour impliquer les opérateurs, vous ne pouvais pas laisser passer x comme argument à une méthode.
  • une expression n'est pas nécessairement un opérateur(s). Ici, vous verrez que Expression peut être un NameExpression (par exemple, le signalement d'une variable locale), un PrimaryExpression (par exemple, en se référant à une primitive littérale), etc
  • Regardez la mise en œuvre de Map.computeIfAbsent() et le blâme de son auteur trop. Ouais je sais qu'ils sont autorisés à le faire et je ne suis pas 🙂
  • Je pense que nous parlons à contre-ici, depuis l'identifiant "x" apparaît deux fois dans l'expression en vertu de la discussion, une fois sur la gauche de l'opérateur d'égalité, et sur la gauche d'un opérateur d'affectation. Je suppose que la discussion était sur l'ancien, depuis l'OP parle de "chargement" de la valeur. La partie de la spécification de vous citer est à propos de l'opérande de gauche d'un opérateur d'affectation. Je le concède, j'ai parlé de manière imprécise. Mon point est que "l'évaluation" du côté gauche de l'expression ne donne pas une sorte de paresseux valeur qui peut changer ou modifier avant l'opération de comparaison évalue.
  • Mon interprétation de l'OP du modèle mental était: 1. évaluer == opérandes gauche à droite. 2. x n'a pas besoin de l'évaluation, il est juste "x" (une erreur). 3. évaluer (x = y) 4. Variable x est mis à jour à la valeur de y, l'expression a la valeur de y, qui est 3. 5. évaluer == de l'opérateur. 6. Récupérer la valeur actuelle de x et de le comparer à 5. Si c'est le cas, ce n'est pas l'ordre d'évaluation qu'ils ont obtenu confus. C'est le sens de "l'évaluation de x".

InformationsquelleAutor John McClane | 2018-12-12