[resulttype] funcname ( parameterlist ) := FUNCTION
code
RETURN retval;
END;
The FUNCTION structure allows you to pass parameters to a set of related attribute definitions. This makes it possible to pass parameters to an attribute that is defined in terms of other non-exported attributes without the need to parameterise all of those as well.
Side-effect actions contained in the code of the FUNCTION must have definition names that must be referenced by the WHEN function to execute.
Example:
//a coordinated set of 3 examples
IMPORT Std;
NameRec := RECORD
STRING5 title := '';
STRING20 fname := '';
STRING20 mname := '';
STRING20 lname := '';
STRING5 name_suffix := '';
STRING3 name_score := '';
END;
MyRecord := RECORD
UNSIGNED id;
STRING uncleanedName;
NameRec Name;
END;
ds := DATASET([{1,'Mr. John Smith JR'},
{2,'Mrs. Susie Samantha Jones 3'},
{3,'Dr. Fred Taylor SR'}],MyRecord);
STRING73 CleanPerson73(STRING inputName) := FUNCTION
suffix :=[ ' 0',' 1',' 2',' 3',' 4',' 5',' 6',' 7',' 8',' 9',
' J',' JR',' S',' SR'];
InWords := Std.Str.CleanSpaces(inputName);
HasSuffix := InWords[LENGTH(TRIM(InWords))-1 ..] IN suffix;
WordCount := LENGTH(TRIM(InWords,LEFT,RIGHT)) -
LENGTH(TRIM(InWords,ALL)) + 1;
HasMiddle := WordCount = 5 OR (WordCount = 4 AND NOT HasSuffix) ;
Sp1 := Std.Str.Find(InWords,' ',1);
Sp2 := Std.Str.Find(InWords,' ',2);
Sp3 := Std.Str.Find(InWords,' ',3);
Sp4 := Std.Str.Find(InWords,' ',4);
STRING5 title := InWords[1..Sp1-1];
STRING20 fname := InWords[Sp1+1..Sp2-1];
STRING20 mname := IF(HasMiddle,InWords[Sp2+1..Sp3-1],'');
STRING20 lname := MAP(HasMiddle AND NOT HasSuffix => InWords[Sp3+1..],
HasMiddle AND HasSuffix => InWords[Sp3+1..Sp4-1],
NOT HasMiddle AND NOT HasSuffix => InWords[Sp2+1..],
NOT HasMiddle AND HasSuffix => InWords[Sp2+1..Sp3-1],
'');
STRING5 name_suffix := IF(HasSuffix,InWords[LENGTH(TRIM(InWords))-1..],'');
STRING3 name_score := '';
RETURN title + fname + mname + lname + name_suffix + name_score;
END;
//Example 1 - a transform to create a row from an uncleaned name
NameRec createRow(STRING inputName) := TRANSFORM
cleanedText := CleanPerson73(inputName);
SELF.title := cleanedText[1..5];
SELF.fname := cleanedText[6..25];
SELF.mname := cleanedText[26..45];
SELF.lname := cleanedText[46..65];
SELF.name_suffix := cleanedText[66..70];
SELF.name_score := cleanedText[71..73];
END;
myRecord t(myRecord l) := TRANSFORM
SELF.Name := ROW(createRow(l.uncleanedName));
SELF := l;
END;
y := PROJECT(ds, t(LEFT));
OUTPUT(y);
//Example 2 - an attribute using that transform to generate the row.
NameRec cleanedName(STRING inputName) := ROW(createRow(inputName));
myRecord t2(myRecord l) := TRANSFORM
SELF.Name := cleanedName(l.uncleanedName);
SELF := l;
END;
y2 := PROJECT(ds, t2(LEFT));
OUTPUT(y2);
//Example 3 = Encapsulate the transform inside the attribute by
// defining a FUNCTION.
NameRec cleanedName2(STRING inputName) := FUNCTION
NameRec createRow := TRANSFORM
cleanedText := CleanPerson73(inputName);
SELF.title := cleanedText[1..5];
SELF.fname := cleanedText[6..25];
SELF.mname := cleanedText[26..45];
SELF.lname := cleanedText[46..65];
SELF.name_suffix := cleanedText[66..70];
SELF.name_score := cleanedText[71..73];
END;
RETURN ROW(createRow);
END;
myRecord t3(myRecord l) := TRANSFORM
SELF.Name := cleanedName2(l.uncleanedName);
SELF := l;
END;
y3 := PROJECT(ds, t3(LEFT));
OUTPUT(y3);
//*************************************************************
//Example using MODULE structure to return multiple values from a FUNCTION
OperateOnNumbers(Number1, Number2) := FUNCTION
result := MODULE
EXPORT Multiplied := Number1 * Number2;
EXPORT Differenced := Number1 - Number2;
EXPORT Summed := Number1 + Number2;
END;
RETURN result;
END;
OUTPUT(OperateOnNumbers(23,22).Multiplied); //506
OUTPUT(OperateOnNumbers(23,22).Differenced); //1
OUTPUT(OperateOnNumbers(23,22).Summed); //45
//*************************************************************
//a FUNCTION with side-effect Action
namesTable := FUNCTION
namesRecord := RECORD
STRING20 surname;
STRING10 forename;
INTEGER2 age := 25;
END;
o := OUTPUT('namesTable used by user <x>');
ds1 := DATASET([{'x','y',22}],namesRecord);
RETURN WHEN(ds1,o);
END;
z := namesTable : PERSIST('z');
//the PERSIST causes the side-effect action to execute only when the PERSIST is re-built
OUTPUT(z);
See Also: MODULE Structure, TRANSFORM Structure, WHEN