progress-4gl
Funciones
Buscar..
Introducción
Una función definida por el usuario en Progress ABL es un módulo de programa reutilizable.
Observaciones
- Una función debe ser declarada en el procedimiento "principal". No puede ser declarado dentro de un procedimiento o dentro de otra función.
- Una función en Progress ABL no es un "ciudadano de primera clase" a diferencia de los lenguajes de programación como Haskell o Javascript. No puede pasar una función como un parámetro de entrada o salida. Sin embargo, puede inviolarlos dinámicamente usando
DYNAMIC-FUNCTION
o el objetoCALL
. - Las funciones de llamada en sus consultas pueden llevar a un mal rendimiento, ya que la comparación de índices se verá afectada. Intente asignar el valor de la función a una variable y use esa variable en la CLASE
WHERE
su lugar.
Función 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").
Partes de la sintaxis en realidad no son necesarias:
/* 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.
Funciones de declaración directa
Se puede reenviar una función, esto es similar a las especificaciones en un archivo de encabezado C. De esa manera, el compilador sabe que una función estará disponible más adelante.
Sin declaraciones de reenvío, la función DEBE ser declarada antes de ser llamada en el código. La declaración de reenvío consta de la especificación de FUNCTION
(nombre de la función, tipo de retorno y tipos de datos de parámetros y orden). Si la declaración hacia adelante no coincide con la función real, el compilador producirá errores y el código no se ejecutará.
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.
Parámetros de entrada múltiples
/ * Esto abrirá un cuadro de mensaje que dice "HOLA MUNDIAL" * /
FUNCTION cat RETURNS CHARACTER ( c AS CHARACTER, d AS CHARACTER):
RETURN c + " " + d.
END.
MESSAGE cat("HELLO", "WORLD") VIEW-AS ALERT-BOX.
Múltiples declaraciones de retorno (pero un solo valor de retorno)
Una función puede tener múltiples declaraciones de retorno y se pueden colocar en diferentes partes de la función real. Sin embargo, todos deben devolver el mismo tipo de datos.
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.
Una función en realidad no tiene que devolver nada en absoluto. Entonces su valor de retorno será? (desconocido). El compilador no detectará esto (pero sus colegas lo evitarán).
/* 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.
Parámetros de salida y entrada-salida
Una función solo puede devolver un solo valor, pero hay una forma de evitarlo: los parámetros no están limitados a los parámetros de entrada. Puede declarar los parámetros INPUT
, OUTPUT
y INPUT-OUTPUT
.
A diferencia de los parámetros INPUT
, debe especificar OUTPUT
o INPUT-OUTPUT
antes de los parámetros.
Algunas convenciones de codificación pueden no gustar, pero se puede hacer.
/* 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.
Aquí hay un ejemplo de un parámetro 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.
Recursion
Ver recursion
Una función puede llamarse a sí misma y así recursionar.
FUNCTION factorial INTEGER (num AS INTEGER).
IF num = 1 THEN
RETURN 1.
ELSE
RETURN num * factorial(num - 1).
END FUNCTION.
DISPLAY factorial(5).
Con las configuraciones estándar (parámetro de inicio), la sesión de Progreso no podrá manejar números muy grandes en este ejemplo. factorial(200)
llenará la pila y generará un error.
Llamada dinámica de una función.
Usando DYNAMIC-FUNCTION
o el objeto CALL
puede llamar dinámicamente a las funciones.
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.
El objeto CALL
no es tan liviano como la FUNCIÓN DINÁMICA. Se puede usar para llamar a diferentes cosas: funciones, procedimientos, programa externo, funciones de DLL de Windows. También puede invocar métodos en objetos y acceder a los que obtienen / configuran.
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.