Récursivité en OpenEdge ABL : exemples et bonnes pratiques

Dans la plupart des applications de gestion, on rencontre tôt ou tard une donnée hiérarchique : une nomenclature produit, un organigramme, une arborescence de catégories, une structure de comptes comptables avec sous-comptes. Le langage ABL (OpenEdge) permet de traiter ces cas avec des procédures ou méthodes récursives, mais c’est un outil qui se manie avec précaution.

Qu’est-ce que la récursivité, concrètement ?

Une procédure récursive est une procédure qui s’appelle elle-même, en général pour traiter un niveau d’une hiérarchie avant de descendre (ou remonter) au niveau suivant. Trois ingrédients sont indispensables :

  • un cas de base : la condition qui arrête la récursion ;
  • un appel récursif qui rapproche du cas de base à chaque itération ;
  • un état transmis (souvent une clé, un niveau de profondeur, ou une temp-table accumulant les résultats).

Sans le premier point, on obtient une récursion infinie — et en ABL, cela se traduit vite par une pile qui explose ou un serveur AppServer qui sature.

Exemple : parcourir une arborescence de catégories

Prenons une table Categorie avec un champ CategorieParentID. On veut lister tous les descendants d’une catégorie donnée.

DEFINE TEMP-TABLE ttResultat NO-UNDO
    FIELD CategorieID   AS INTEGER
    FIELD Libelle       AS CHARACTER
    FIELD Profondeur    AS INTEGER.

PROCEDURE ListerDescendants:
    DEFINE INPUT PARAMETER piCategorieID AS INTEGER NO-UNDO.
    DEFINE INPUT PARAMETER piProfondeur  AS INTEGER NO-UNDO.

    FOR EACH Categorie NO-LOCK
        WHERE Categorie.CategorieParentID = piCategorieID:

        CREATE ttResultat.
        ASSIGN
            ttResultat.CategorieID = Categorie.CategorieID
            ttResultat.Libelle     = Categorie.Libelle
            ttResultat.Profondeur  = piProfondeur.

        /* Appel récursif sur les enfants de la catégorie courante */
        RUN ListerDescendants(Categorie.CategorieID, piProfondeur + 1).
    END.

END PROCEDURE.

/* Point d'entrée */
RUN ListerDescendants(0, 1).

Ici, le cas de base n’est pas explicite sous forme de IF : c’est le FOR EACH qui, lorsqu’il ne trouve plus d’enfant, arrête naturellement la récursion pour cette branche.

Les pièges les plus fréquents

1. L’absence de protection contre les cycles. Si les données contiennent une boucle (une catégorie qui se retrouve, par erreur, son propre ancêtre), la récursion ne s’arrête jamais. Sur des données reprises d’un import ou d’une migration, ce n’est pas un cas d’école : ça arrive. Une protection simple consiste à transmettre la liste des ID déjà visités et à vérifier qu’on n’y revient pas.

2. La profondeur de pile. ABL n’a pas de limite de récursion documentée universelle, mais au-delà de quelques centaines de niveaux, les performances et la stabilité se dégradent. Pour des hiérarchies très profondes ou de volumétrie inconnue, une version itérative avec une temp-table faisant office de pile (PUSH/POP manuel) est souvent plus sûre.

3. Le coût des FOR EACH imbriqués sur de gros volumes. Chaque appel récursif relance une lecture. Sur une table de plusieurs centaines de milliers de lignes, pensez à indexer CategorieParentID et à mesurer avant d’optimiser.

4. Le débogage. Une pile d’appels récursifs est plus difficile à suivre pas à pas qu’une boucle classique. Ajouter un paramètre de profondeur (comme piProfondeur ci-dessus) sert aussi de fil d’Ariane dans les logs.

Quand préférer une version itérative

Si la hiérarchie est peu profonde et le volume raisonnable (menus, catégories, organigrammes de quelques centaines d’entrées), la récursion reste la solution la plus lisible. Si le volume est important ou incertain, ou si le code doit tourner sur un AppServer avec des contraintes mémoire strictes, une version itérative avec une temp-table jouant le rôle de pile est plus robuste dans la durée.

En résumé

La récursivité en ABL n’a rien d’exotique : elle repose sur les mêmes règles que dans n’importe quel langage — un cas de base solide, un état qui progresse, et une vigilance particulière sur les cycles et la volumétrie. Sur du code Progress ancien (v9 et antérieur), il n’est pas rare de trouver des récursions écrites sans protection contre les boucles : c’est un bon point de départ pour un audit de code.


Besoin d’un audit de vos développements Progress / OpenEdge, ou d’une formation pour votre équipe sur ces bonnes pratiques ? Contactez-moi ou consultez ma page audit Progress / OpenEdge.

Retour en haut