サーチ…
前書き
Progress ABLのユーザー定義関数は、再利用可能なプログラムモジュールです。
備考
- 関数は "main"プロシージャで宣言しなければなりません。プロシージャ内または別の関数内で宣言することはできません。
- プログレスABLの関数は、HaskellやJavascriptのようなプログラミング言語とは異なり、「ファーストクラスの市民」ではありません。関数を入力または出力パラメーターとして渡すことはできません。ただし、
DYNAMIC-FUNCTION
またはCALL
オブジェクトを使用して動的に呼び出すことはできます。 - クエリ内の関数を呼び出すと、インデックスの一致が損なわれるため、パフォーマンスが低下する可能性があります。関数の値を変数に代入し、その変数を代わりに
WHERE
句で使用してください。
シンプルな関数
/* 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").
構文の一部は実際には必要ありません。
/* 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.
フォワード宣言関数
関数を前方宣言することができますが、これはCヘッダーファイルの仕様に似ています。このようにして、コンパイラは関数が後で利用可能になることを知っています。
前方宣言がなければ、関数はコード内で呼び出される前に宣言されなくてはなりません(MUST)。前方宣言は、 FUNCTION
指定(関数名、戻り値の型、およびパラメーターのデータ型と順序)で構成されます。前方宣言が実際の関数と一致しない場合、コンパイラはエラーを生成し、コードは実行されません。
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.
複数の入力パラメータ
/ *これは "HELLO WORLD"というメッセージボックスをポップアップする* /
FUNCTION cat RETURNS CHARACTER ( c AS CHARACTER, d AS CHARACTER):
RETURN c + " " + d.
END.
MESSAGE cat("HELLO", "WORLD") VIEW-AS ALERT-BOX.
複数のreturn文(しかし、単一の戻り値)
関数は複数のreturn文を持つことができ、実際の関数の異なる部分に配置することができます。彼らはすべて同じデータ型を返す必要があります。
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.
関数は実際に何も返す必要はありません。次に戻り値は? (道の)。コンパイラはこれをキャッチしません(しかし、あなたの同僚はそれを避けるでしょう)。
/* 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.
出力および入出力パラメータ
関数は単一の値だけを返すことができますが、そのための方法は1つあります。パラメータは入力パラメータに限定されません。 INPUT
、 OUTPUT
、およびINPUT-OUTPUT
パラメータを宣言できます。
INPUT
パラメータとは異なり、パラメータの前にOUTPUT
またはINPUT-OUTPUT
指定する必要があります。
いくつかのコーディング規約ではこれが気に入らないかもしれませんが、それは可能です。
/* 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.
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.
再帰
再帰を参照
関数はそれ自身を呼び出して再帰することができます。
FUNCTION factorial INTEGER (num AS INTEGER).
IF num = 1 THEN
RETURN 1.
ELSE
RETURN num * factorial(num - 1).
END FUNCTION.
DISPLAY factorial(5).
標準設定(起動パラメータ)では、この例ではProgressセッションは非常に大きな数値を処理できません。 factorial(200)
がスタックを埋めるため、エラーが発生します。
関数の動的呼び出し
DYNAMIC-FUNCTION
またはCALL
オブジェクトを使用すると、動的に関数を呼び出すことができます。
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.
CALL
オブジェクトは、DYNAMIC-FUNCTIONほど軽量ではありません。関数、プロシージャ、外部プログラム、WindowsのDLL関数など、さまざまなものを呼び出すために使用できます。また、オブジェクトのメソッドを呼び出したり、getter / setterにアクセスしたりすることもできます。
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.