Une des raisons pour lesquelles l’ABAP m’énerve est que ce langage me met des bâtons dans les roues lorsque je cherche à réutiliser mes habitudes de programmation en mode « défensif ».

Prenons un exemple où l’on balaye une innocente table (disons les lignes d’une facture) ; le curseur est nommé x et on veut un compteur qui somme le contenu de la colonne un_autre_champ (un prix par exemple), plus une valeur calculée arbitrairement (par exemple une taxe) si la colonne un_champ prend une valeur quelconque. Cela donne :

En PL/SQL (langage d’Oracle Applications, entre autres) :

.FOR x IN (SELECT * FROM matable) LOOP
. DECLARE
. v VARCHAR(2) := 0 ;
. BEGIN
. IF x.un_champ = ... THEN
. v = c_une_valeur ;
. END IF ;
. compteur = compteur + v + x.un_autre_champ ;
. END ;
.END LOOP ;

En ABAP (langage de SAP exclusivement) :

.SELECT * FROM matable INTO x.
. DATA v TYPE c VALUE '0'.
. IF x-un_champ = ... .
. v = c_une_valeur.
. ENDIF.
. compteur = compteur + v + x-un_autre_champ.
.ENDSELECT. " Fin de la boucle

Ces deux codes, bien que fort semblables aux différences syntaxiques superficielles près, ne feront en fait pas la même chose. Comme j’ai dit, on ne recalcule v que dans certains cas.

En PL/SQL, la déclaration de v à l’intérieur de la boucle (donc comme variable la moins globale possible), permet de redéclarer et réinitialiser à zéro v à chaque tour de boucle.

En ABAP, la combine ne fonctionne pas. Le code ci-dessus ne réinitialisera pas v à 0. Il n’y a aucune erreur due au fait que j’ai redéclaré ma variable à chaque tour de boucle. Entre deux tours, v gardera sa valeur !

On peut corriger de mille manières, par exemple en prévoyant une deuxième branche ELSEIF, qui effectue v = 0.
Ou bien, tout bêtement, en réinitialisant à chaque début de boucle : CLEAR v. En ABAP, c’est pas plus difficile que cela.

Mais. Ici il n’y a qu’une variable.
Dans la réalité des dizaines de variables, compteurs, structures, tableaux, déclarés un peu n’importe où, se partagent l’attention du programmeur. Je suis un ferme partisan de l’initialisation au moment de la déclaration, de la durée de vie la plus minimaliste possible des variables, un ennemi des variables globales et un accro de la réduction du scope. Une variable qui n’existe pas ne me gênera jamais.

L’ABAP n’est pas un compilateur très coopératif pour ce genre de programmation. Les variables restent en général globales à un (sous-)programme, et les orgies de CLEAR parsèment les boucles. Je vois ressurgir des classes entières de bugs que je ne connaissais pas en PL/SQL. Et, je le redis, le PL/SQL n’a rien de très sexy ou avancé, c’est juste un langage bien foutu pour son boulot (fortement inspiré du Pascal, ce qui me plaît).

NB : L’exemple ci-dessus néglige le fait que sous Oracle un ordre SQL aurait suffit, même pas la peine de dégainer le PL :
SELECT SUM(un_autre_champ + DECODE (un_champ, ..., c_une_valeur) ) FROM ma_table ou une autre astuce de la même veine. Je ne pense pas que ce soit facilement possible en ABAP pur - qu’on me corrige si je me trompe.

(Dernière minute : Et en plus, il semblerait que le Visual Basic (nouvelle version) soit aussi victime de ce problème ! Différence entre scope et durée de vie d’une variable, dit l’auteur. En tout cas c’est source de bugs...)