progress-4gl
Les fonctions
Recherche…
Introduction
Une fonction définie par l'utilisateur dans Progress ABL est un module de programme réutilisable.
Remarques
- Une fonction doit être déclarée dans la procédure "principale". Il ne peut pas être déclaré dans une procédure ou dans une autre fonction.
- Une fonction en cours ABL n'est pas un "citoyen de première classe" contrairement aux langages de programmation comme Haskell ou Javascript. Vous ne pouvez pas transmettre une fonction en tant que paramètre d'entrée ou de sortie. Vous pouvez cependant les appeler dynamiquement en utilisant
DYNAMIC-FUNCTION
ou l'objetCALL
. - L'appel de fonctions dans vos requêtes peut entraîner de mauvaises performances, car la correspondance avec les index est préjudiciable. Essayez d'affecter la valeur de la fonction à une variable et utilisez cette variable dans la
WHERE
WHERE à la place.
Fonction simple
/* This function returns TRUE if input is the letter "b" and false otherwise */
FUNCTION isTheLetterB RETURNS LOGICAL (INPUT pcString AS CHARACTER):
IF pcString = "B" THEN
RETURN TRUE.
ELSE
RETURN FALSE.
END FUNCTION.
/* Calling the function with "b" as input - TRUE expected */
DISPLAY isTheLetterB("b").
/* Calling the function with "r" as input - FALSE expected */
DISPLAY isTheLetterB("r").
Certaines parties de la syntaxe ne sont en fait pas nécessaires:
/* RETURNS isn't required, INPUT isn't required on INPUT-parameters */
FUNCTION isTheLetterB LOGICAL (pcString AS CHARACTER):
IF pcString = "B" THEN
RETURN TRUE.
ELSE
RETURN FALSE.
/* END FUNCTION can be replaced with END */
END.
Fonctions de déclaration anticipée
Une fonction peut être déclarée en avant, ceci est similaire aux spécifications d'un fichier d'en-tête C. De cette manière, le compilateur sait qu'une fonction sera disponible ultérieurement.
Sans déclarations directes, la fonction DOIT être déclarée avant d'être appelée dans le code. La déclaration forward comprend la spécification FUNCTION
(nom de la fonction, type de retour et types de données et ordre des paramètres). Si la déclaration forward ne correspond pas à la fonction réelle, le compilateur produira des erreurs et le code ne pourra pas s'exécuter.
FUNCTION dividableByThree LOGICAL (piNumber AS INTEGER) FORWARD.
DISPLAY dividableByThree(9).
FUNCTION dividableByThree LOGICAL (piNumber AS INTEGER):
IF piNumber MODULO 3 = 0 THEN
RETURN TRUE.
ELSE
RETURN FALSE.
END.
Paramètres d'entrée multiples
/ * Cela va faire apparaître une boîte de message disant "HELLO WORLD" * /
FUNCTION cat RETURNS CHARACTER ( c AS CHARACTER, d AS CHARACTER):
RETURN c + " " + d.
END.
MESSAGE cat("HELLO", "WORLD") VIEW-AS ALERT-BOX.
Instructions de retour multiples (mais une seule valeur de retour)
Une fonction peut avoir plusieurs déclarations de retour et elles peuvent être placées dans différentes parties de la fonction réelle. Cependant, ils doivent tous retourner le même type de données.
FUNCTION returning DATE ( dat AS DATE):
IF dat < TODAY THEN DO:
DISPLAY "<".
RETURN dat - 200.
END.
ELSE DO:
DISPLAY ">".
RETURN TODAY.
END.
END.
MESSAGE returning(TODAY + RANDOM(-50, 50)) VIEW-AS ALERT-BOX.
Une fonction n'a pas besoin de retourner quoi que ce soit. Alors, la valeur de retour sera? (inconnu). Le compilateur n'attrapera pas cela (mais vos collègues l'éviteront donc).
/* This function will only return TRUE or ?, never FALSE, so it might lead to troubles */
FUNCTION inTheFuture LOGICAL ( dat AS DATE):
IF dat > TODAY THEN DO:
RETURN TRUE.
END.
END.
MESSAGE inTheFuture(TODAY + RANDOM(-50, 50)) VIEW-AS ALERT-BOX.
Paramètres de sortie et d'entrée-sortie
Une fonction ne peut renvoyer qu'une seule valeur mais il y a un moyen de contourner cela: les paramètres ne sont pas limités aux paramètres d'entrée. Vous pouvez déclarer les paramètres INPUT
, OUTPUT
et INPUT-OUTPUT
.
Contrairement aux paramètres INPUT
, vous devez spécifier OUTPUT
ou INPUT-OUTPUT
avant les paramètres.
Certaines conventions de codage peuvent ne pas aimer cela, mais cela peut être fait.
/* Function will add numbers and return a sum (AddSomSumbers(6) = 6 + 5 + 4 + 3 + 2 + 1 = 21 */
/* It will also have a 1% per iteration of failing */
/* To handle that possibility we will have a status output parameter */
FUNCTION AddSomeNumbers INTEGER ( INPUT number AS INTEGER, OUTPUT procstatus AS CHARACTER):
procStatus = "processing".
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DEFINE VARIABLE n AS INTEGER NO-UNDO.
/* Iterate number times */
DO i = 1 TO number:
/* Do something */
n = n + i.
/* Fake a 1% chance for an error that breaks the function */
IF RANDOM(1,100) = 1 THEN
RETURN 0.
END.
procStatus = "done".
RETURN n.
END.
DEFINE VARIABLE ret AS INTEGER NO-UNDO.
DEFINE VARIABLE stat AS CHARACTER NO-UNDO.
/* Call the function */
ret = AddSomeNumbers(30, OUTPUT stat).
/* If "stat" is done we made it! */
IF stat = "done" THEN DO:
MESSAGE "We did it! Sum:" ret VIEW-AS ALERT-BOX.
END.
ELSE DO:
MESSAGE "An error occured" VIEW-AS ALERT-BOX ERROR.
END.
Voici un exemple de paramètre INPUT-OUTPUT
:
/* Function doubles a string and returns the length of the new string */
FUNCTION doubleString RETURN INTEGER (INPUT-OUTPUT str AS CHARACTER).
str = str + str.
RETURN LENGTH(str).
END.
DEFINE VARIABLE str AS CHARACTER NO-UNDO.
DEFINE VARIABLE len AS INTEGER NO-UNDO.
str = "HELLO".
len = doubleString(INPUT-OUTPUT str).
MESSAGE
"New string: " str SKIP
"Length: " len VIEW-AS ALERT-BOX.
Récursivité
Voir récursivité
Une fonction peut s'appeler elle-même et, par conséquent, se rétablir.
FUNCTION factorial INTEGER (num AS INTEGER).
IF num = 1 THEN
RETURN 1.
ELSE
RETURN num * factorial(num - 1).
END FUNCTION.
DISPLAY factorial(5).
Avec les paramètres standard (paramètre de démarrage), la session Progress ne sera pas capable de gérer des nombres très importants dans cet exemple. factorial(200)
remplira la pile et générera une erreur.
Appel dynamique d'une fonction
En utilisant DYNAMIC-FUNCTION
ou CALL
-object, vous pouvez appeler dynamiquement des fonctions.
DEFINE VARIABLE posY AS INTEGER NO-UNDO.
DEFINE VARIABLE posX AS INTEGER NO-UNDO.
DEFINE VARIABLE OKkeys AS CHARACTER NO-UNDO INIT "QLDRUS".
DEFINE VARIABLE Step AS INTEGER NO-UNDO INIT 1.
DEFINE VARIABLE moved AS LOGICAL NO-UNDO.
/* Set original position */
posY = 10.
posX = 10.
/* Move up (y coordinates - steps ) */
FUNCTION moveU LOGICAL (INPUT steps AS INTEGER):
IF posY = 0 THEN
RETURN FALSE.
posY = posY - steps.
IF posY < 0 THEN
posY = 0.
RETURN TRUE.
END FUNCTION.
/* Move down (y coordinates + steps ) */
FUNCTION moveD LOGICAL (INPUT steps AS INTEGER):
IF posY = 20 THEN
RETURN FALSE.
posY = posY + steps.
IF posY > 20 THEN
posY = 20.
END FUNCTION.
/* Move left (x coordinates - steps ) */
FUNCTION moveL LOGICAL (INPUT steps AS INTEGER):
IF posX = 0 THEN
RETURN FALSE.
posX = posX - steps.
IF posX < 0 THEN
posX = 0.
RETURN TRUE.
END FUNCTION.
/* Move down (x coordinates + steps ) */
FUNCTION moveR LOGICAL (INPUT steps AS INTEGER):
IF posX = 20 THEN
RETURN FALSE.
posX = posX + steps.
IF posX > 20 THEN
posX = 20.
END FUNCTION.
REPEAT:
DISPLAY posX posY step WITH FRAME x1 1 DOWN.
READKEY.
IF INDEX(OKKeys, CHR(LASTKEY)) <> 0 THEN DO:
IF CHR(LASTKEY) = "q" THEN LEAVE.
IF CAPS(CHR(LASTKEY)) = "s" THEN UPDATE step WITH FRAME x1.
ELSE DO:
moved = DYNAMIC-FUNCTION("move" + CAPS(CHR(LASTKEY)), INPUT step).
IF moved = FALSE THEN
MESSAGE "Out of bounds".
END.
END.
END.
L'objet CALL
n'est pas aussi léger que la DYNAMIC-FUNCTION. Il peut être utilisé pour appeler différentes choses: fonctions, procédures, programme externe, fonctions DLL Windows. Il peut également invoquer des méthodes sur des objets et accéder à des getters / setters.
DEFINE VARIABLE functionHandle AS HANDLE NO-UNDO.
DEFINE VARIABLE returnvalue AS CHARACTER NO-UNDO.
FUNCTION isPalindrome LOGICAL (INPUT txt AS CHARACTER, OUTPUT txtBackwards AS CHARACTER):
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DO i = LENGTH(txt) TO 1 BY -1:
txtBackwards = txtBackwards + SUBSTRING(txt, i, 1).
END.
IF txt = txtBackwards THEN
RETURN TRUE.
ELSE
RETURN FALSE.
END FUNCTION.
CREATE CALL functionHandle.
functionHandle:CALL-NAME = "isPalindrome".
/* Sets CALL-TYPE to the default */
functionHandle:CALL-TYPE = FUNCTION-CALL-TYPE.
functionHandle:NUM-PARAMETERS = 2.
functionHandle:SET-PARAMETER(1, "CHARACTER", "INPUT", "HELLO WORLD").
functionHandle:SET-PARAMETER(2, "CHARACTER", "OUTPUT", returnvalue).
functionHandle:INVOKE.
MESSAGE "Text backwards: " returnvalue "Is it a palindrome? " functionHandle:RETURN-VALUE VIEW-AS ALERT-BOX.
DELETE OBJECT functionHandle.
CREATE CALL functionHandle.
functionHandle:CALL-NAME = "isPalindrome".
/* Sets CALL-TYPE to the default */
functionHandle:CALL-TYPE = FUNCTION-CALL-TYPE.
functionHandle:NUM-PARAMETERS = 2.
functionHandle:SET-PARAMETER(1, "CHARACTER", "INPUT", "ANNA").
functionHandle:SET-PARAMETER(2, "CHARACTER", "OUTPUT", returnvalue).
functionHandle:INVOKE.
MESSAGE "Text backwards: " returnvalue "Is it a palindrome? " functionHandle:RETURN-VALUE VIEW-AS ALERT-BOX.
DELETE OBJECT functionHandle.