Skip to main content

Function Definitions (Parameter Passing)

All of the basic Definition types can also become functions by defining them to accept passed parameters (arguments). The fact that it receives parameters doesn't change the essential nature of the Definition's type, it simply makes it more flexible.

Parameter definitions always appear in parentheses attached to the Definition's name. You may define the function to receive as many parameters as needed to create the desired functionality by simply separating each succeeding parameter definition with a comma.

The format of parameter definitions is as follows:

DefinitionName( [ ValueType ] AliasName [ =DefaultValue ] ) := expression;

ValueTypeOptional. Specifies the type of data being passed. If omitted, the default is INTEGER (see Value Types). This also may include the CONST keyword (see CONST) to indicate that the passed value will always be treated as a constant.
AliasNameNames the parameter for use in the expression.
DefaultValueOptional. Provides the value to use in the expression if the parameter is omitted. The DefaultValue may be the keyword ALL if the ValueType is SET (see the SET keyword) to indicate all possible values for that type of set, or empty square brackets ([ ]) to indicate no possible value for that type of set.
expressionThe function's operation for which the parameters are used.

Simple Value Type Parameters

If the optional ValueType is any of the simple types (BOOLEAN, INTEGER, REAL, DECIMAL, STRING, QSTRING, UNICODE, DATA, VARSTRING, VARUNICODE), the ValueType may include the CONST keyword (see CONST) to indicate that the passed value will always be treated as a constant (typically used only in ECL prototypes of external functions).

ValueDefinition := 15;
FirstFunction(INTEGER x=5) := x + 5;
          //takes an integer parameter named "x" and "x" is used in the
          //arithmetic expression to indicate the usage of the parameter
          
SecondDefinition := FirstFunction(ValueDefinition);
          // The value of SecondDefinition is 20
          
ThirdDefinition := FirstFunction();
          // The value of ThirdDefinition is 10, omitting the parameter

SET Parameters

The DefaultValue for SET parameters may be a default set of values, the keyword ALL to indicate all possible values for that type of set, or empty square brackets ([ ]) to indicate no possible value for that type of set (and empty set).

SET OF INTEGER1 SetValues := [5,10,15,20];

IsInSetFunction(SET OF INTEGER1 x=SetValues,y) := y IN x;

OUTPUT(IsInSetFunction([1,2,3,4],5)); //false
OUTPUT(IsInSetFunction(,5)); // true

Passing DATASET Parameters

Passing a DATASET or a derived recordset as a parameter may be accomplished using the following syntax:

DefinitionName( DATASET( recstruct ) AliasName ) := expression;

The required recstruct names the RECORD structure that defines the layout of fields in the passed DATASET parameter. The recstruct may alternatively use the RECORDOF function. The required AliasName names the dataset for use in the function and is used in the Definition's expression to indicate where in the operation the passed parameter is to be used. See the DATASET as a Value Type discussion in the DATASET documentation for further examples.

MyRec := {STRING1 Letter};
    
SomeFile := DATASET([{'A'},{'B'},{'C'},{'D'},{'E'}],MyRec);

FilteredDS(DATASET(MyRec) ds) := ds(Letter NOT IN ['A','C','E']);
           //passed dataset referenced as "ds" in expression

OUTPUT(FilteredDS(SomeFile));

Passing DICTIONARY Parameters

Passing a DICTIONARY as a parameter may be accomplished using the following syntax:

DefinitionName( DICTIONARY( structure ) AliasName ) := expression;

The required structure parameter is the RECORD structure that defines the layout of fields in the passed DICTIONARY parameter (usually defined inline). The required AliasName names the DICTIONARY for use in the function and is used in the Definition's expression to indicate where in the operation the passed parameter is to be used. See the DICTIONARY as a Value Type discussion in the DICTIONARY documentation.

rec := RECORD
  STRING10  color;
  UNSIGNED1 code; 
  STRING10  name;
END;
Ds := DATASET([{'Black' ,0 , 'Fred'},
               {'Brown' ,1 , 'Seth'},
               {'Red'   ,2 , 'Sue'},
               {'White' ,3 , 'Jo'}], rec);

DsDCT := DICTIONARY(DS,{color => DS});

DCTrec := RECORD 
  STRING10 color => 
  UNSIGNED1 code,
  STRING10 name,
END;
InlineDCT := DICTIONARY([{'Black' => 0 , 'Fred'},
                         {'Brown' => 1 , 'Sam'},
                         {'Red'   => 2 , 'Sue'},
                         {'White' => 3 , 'Jo'} ], 
                        DCTrec);

MyDCTfunc(DICTIONARY(DCTrec) DCT,STRING10 key) := DCT[key].name;

MyDCTfunc(InlineDCT,'White');  //Jo
MyDCTfunc(DsDCT,'Brown');      //Seth

Passing Typeless Parameters

Passing parameters of any type may be accomplished using the keyword ANY as the passed value type:

DefinitionName ( ANY AliasName ) := expression;

a := 10;
b := 20;
c := '1';
d := '2';
e := '3';
f := '4';
s1 := [c,d];
s2 := [e,f];

ds1 := DATASET(s1,{STRING1 ltr});
ds2 := DATASET(s2,{STRING1 ltr});

MyFunc(ANY l, ANY r) := l + r;

MyFunc(a,b);      //returns 30
MyFunc(a,c);      //returns '101'
MyFunc(c,d);      //returns '12'
MyFunc(s1,s2);    //returns a set: ['1','2','3','4']
MyFunc(ds1,ds2);  //returns 4 records: '1', '2', '3', and '4'

Passing Function Parameters

Passing a Function as a parameter may be accomplished using either of the following syntax options as the ValueType for the parameter:

FunctionName(parameters)

PrototypeName

FunctionNameThe name of a function, the type of which may be passed as a parameter.
parametersThe parameter definitions for the FunctionName parameter.
PrototypeNameThe name of a previously defined function to use as the type of function that may be passed as a parameter.

The following code provides examples of both methods:

//a Function prototype:
INTEGER actionPrototype(INTEGER v1, INTEGER v2) := 0;

INTEGER aveValues(INTEGER v1, INTEGER v2) := (v1 + v2) DIV 2;
INTEGER addValues(INTEGER v1, INTEGER v2) := v1 + v2;
INTEGER multiValues(INTEGER v1, INTEGER v2) := v1 * v2;

//a Function prototype using a function prototype:
INTEGER applyPrototype(INTEGER v1, actionPrototype actionFunc) := 0;

//using the Function prototype and a default value:
INTEGER applyValue2(INTEGER v1,
                    actionPrototype actionFunc = aveValues) :=
                    actionFunc(v1, v1+1)*2;
                       
//Defining the Function parameter inline, witha default value:
INTEGER applyValue4(INTEGER v1,
                    INTEGER actionFunc(INTEGER v1,INTEGER v2) = aveValues)
               := actionFunc(v1, v1+1)*4; 
INTEGER doApplyValue(INTEGER v1,
                     INTEGER actionFunc(INTEGER v1, INTEGER v2))
        := applyValue2(v1+1, actionFunc);
       
//producing simple results:
OUTPUT(applyValue2(1));                           // 2
OUTPUT(applyValue2(2));                           // 4
OUTPUT(applyValue2(1, addValues));                // 6
OUTPUT(applyValue2(2, addValues));                // 10
OUTPUT(applyValue2(1, multiValues));              // 4
OUTPUT(applyValue2(2, multiValues));              // 12
OUTPUT(doApplyValue(1, multiValues));             // 12
OUTPUT(doApplyValue(2, multiValues));             // 24


          
//A definition taking function parameters which themselves
//have parameters that are functions...

STRING doMany(INTEGER v1,
              INTEGER firstAction(INTEGER v1,
                                  INTEGER actionFunc(INTEGER v1,INTEGER v2)),
              INTEGER secondAction(INTEGER v1,
                                   INTEGER actionFunc(INTEGER v1,INTEGER v2)),
              INTEGER actionFunc(INTEGER v1,INTEGER v2)) 
       := (STRING)firstAction(v1, actionFunc) + ':' + (STRING)secondaction(v1, actionFunc);

OUTPUT(doMany(1, applyValue2, applyValue4, addValues));
     // produces "6:12"
     
OUTPUT(doMany(2, applyValue4, applyValue2,multiValues));
     // produces "24:12" 

Passing NAMED Parameters

Passing values to a function defined to receive multiple parameters, many of which have default values (and are therefore omittable), is usually accomplished by "counting commas" to ensure that the values you choose to pass are passed to the correct parameter by the parameter's position in the list. This method becomes untenable when there are many optional parameters.

The easier method is to use the following NAMED parameter syntax, which eliminates the need to include extraneous commas as place holders to put the passed values in the proper parameters:

Attr := FunctionName( [ NAMED ] AliasName := value );

NAMEDOptional. Required only when the AliasName clashes with a reserved word.
AliasNameThe names of the parameter in the definition's function definition. This must be a valid label (See Definition Name Rules)
valueThe value to pass to the parameter.

This syntax is used in the call to the function and allows you to pass values to specific parameters by their AliasName, without regard for their position in the list. All unnamed parameters passed must precede any NAMED parameters.

outputRow(BOOLEAN showA = FALSE, BOOLEAN showB = FALSE,
          BOOLEAN showC = FALSE, STRING aValue = 'abc',
          INTEGER bValue = 10, BOOLEAN cValue = TRUE) :=
  OUTPUT(IF(showA,' a='+aValue,'')+
         IF(showB,' b='+(STRING)bValue,'')+
         IF(showc,' c='+(STRING)cValue,''));

outputRow();                    //produce blanks
outputRow(TRUE);                //produce "a=abc"
outputRow(,,TRUE);              //produce "c=TRUE"
outputRow(NAMED showB := TRUE); //produce "b=10"

outputRow(TRUE, NAMED aValue := 'Changed value');
                                //produce "a=Changed value"

outputRow(,,,'Changed value2',NAMED showA := TRUE);
                                //produce "a=Changed value2"

outputRow(showB := TRUE);       //produce "b=10"

outputRow(TRUE, aValue := 'Changed value');
outputRow(,,,'Changed value2',showA := TRUE);