Greg's Devblog Par un développeur, pour les développeurs

17oct/102

Evaluation non paresseuse en Java

A ma grande surprise, il est possible en Java d'utiliser les opérateurs binaires '&' et '|' sur des booléens, alors que j'étais persuadés qu'ils étaient limités aux opérations binaires sur les entiers...

En fait, Ces symboles font presque la même chose que '&&' et '||', mais sans évaluation paresseuse. Etudions ce que fait le code suivant :

if (checkFoo() && checkBar()){
	...
}

Ici, si checkFoo retour FALSE, il n'est pas utile d'évalué checkBar, puisqu'on sait par avance que le résultat du test dans le if sera FALSE. Par évaluation paresseuse, checkBar n'est donc pas appelé... Or, que se passe-t-il si dans checkBar on avait un effet de bord ? Car comme celui-ci n'est pas effectué, cela pourrait changer l'execution du programme.

Avec le code suivant, on passe outre l'évaluation paresseuse :

if (checkFoo() & checkBar()){
	...
}

Le résultat du test sera inchangé, mais par contre cette fois-ci checkBar sera appelée.

Je pense que dans l'ensemble il est rare d'avoir besoin de ce genre de subtilité, et j'utilise toujours l'évaluation paresseuse (qui, par définition, est sensé être plus rapide...) ; mais on ne sait jamais, ça pourrait servir un jour :)

A noter qu'on peut par contre trouver des cas où il est nécessaire d'avoir une évaluation paresseuse pour que le programme tourne correctement. Voici un en C/C++, et un autre en Java :

my_type *p = getThing();
if ((p != NULL) && p->bool_value){
	...
}
MyObj obj = getObject();
if ((obj != null) && obj.isAlive()){
	...
}

Dans les 2 cas, l'évaluation paresseuse va permettre de garantir que l'expression de droite ne sera évaluée que si la première est validée. Dans la version C, on a donc la garanti que le pointeur sera valide (ou en tout cas non null), et de même avec la référence en Java.

Commentaires (2) Trackbacks (0)
  1. N’est-il pas abusif de parler d’évaluation paresseuse dans le cas de if (x && y) { … } ? Iirc, on parlera d’évaluation paresseuse plutôt pour expliquer qu’un langage fonctionnel commence dans fun(foo(…), bar(…)) l’exécution par fun() en laissant les arguments effectifs non-définis et en appelant les fonctions foo() et bar() à la demande uniquement (dans le cas où l’argument est effectivement utilisé dans le corps de fun().

    Ici, on est plus proche d’une exécution conditionnelle :
    if (x && y && z) brol(); est une version raccourcie de if (x) { if (y) { if (z) brol(); } } }

    Mais bon, j’ai jamais été un caïd de nomenclature, non plus.

    • Je dirais que ça se discute. D’un côté, on appelle ça le « short-circuit », en anglais, comme en témoigne cet article Wikipedia : http://en.wikipedia.org/wiki/Short-circuit_evaluation
      De l’autre, tu donnes un exemple très pertinent. En fait, pour expliquer le pourquoi de l’évaluation paresseuse en Haskell, j’ai vu un tuto qui disait qu’en programmation, quand on fait if c then a else b, c’est toujours paresseux car si ‘c’, alors seul ‘a’ est évalué, et pas b… Et donc dans un langage non paresseux, faire une fonction qui prend en argument ‘a’ et ‘b’ et a le même comportement que le if, c’est mort…
      Sauf que du coup, la réécriture que tu montres avec les if imbriqués rentrent exactement dans le cadre de cet exemple de base de l’évaluation paresseuse…

      Mais bon, j’ai bien compris que tu voulais juste me faire chier ;)


Laisser un commentaire


Aucun trackbacks pour l'instant