WHILE ( You Waited)…
…a new loop function is provided in FileMaker 18 !
Until now, recursion was the only way to tackle repetitive calculations. Now the new While() function may be used in all places where calculations are accepted. And it is not necessary to write a Custom Function for that purpose. That, in essence is the news.
In a recent article for the German FileMaker-Magazine we did explore the new functionality. (auf Deutsch)
The WHILE function allows you to define a calculation that needs a certain number of repetitions in order to provide a result. The actual number of repetitions need not to be exactly known at the time of definition but can be determined at execution time.
We now have the possibility for the following loop control structures:
Count-controlled loops
FOR counter = 1..n DO {instructionBlock}
A group of steps (instructionBlock) is repeated exactly n times.
Condition-controlled loops
WHILE <condition> DO {instructionBlock}
A group of steps (instructionBlock) is only executed and possibly repeated if <condition> is true in the beginning and before every repetition.
REPEAT {instructionBlock} UNTIL <condition>
A group of steps (instructionBlock) is at least once executed and possibly repeated until <condition> is true after any repetition.
Off course, since it is FileMaker, there is built-in safety to prevent what happens with the roller coaster: eternal loops that would require the user to forcefully end the program.
Just as with Recursion only 50.000 repetitions are allowed before the function terminates reporting an error: "?"
Also new in FileMaker 18, the number of allowed repetitions may be controlled with SetRecursion() function.
Every programming language must find a way to implement functionality in syntax, a rule system describing the allowed sentences or constructs in that language. And every designer tries to make the syntax similar to comparable wordings in that language.
In FileMaker, the functional constructor consists of a designating keyword followed by a list of parameters, enclosed in round brackets and separated from each other by semicolon. A specialty worth to be noted is the first parameter, a separate block to define the local variables for the function, comparable to a similar construct used in the syntax for LET(). Local variables exist and are accessible only from inside the function and while that function is executed. They may be used in any of the other three parameters.
Even more local variables may be defined inside the <repeatedBlock>, but they will be available and accessible inside that block in one repetition only!
The result of executing a function is always a value returned to the calling part of the program. And here another specialty in FileMaker, the data type of the result can be any valid type: text, number, date, time, timestamp or even a BLOB - binary large object - which is anything you may store in a container field.
The formal description in the FileMaker 18 Help manual though needs clarification. Here is an alternative:
WHILE ( [ <variableBlock> ]; <condition>; [ <repeatedBlock> ]; <resultExpression> )
How do you read that syntax? Whatever is typed in italics is a descriptive word for a part in the language that needs further explanation. Everything else has to be taken as literal.
Thus we have four parts in that statement which need further explanation. The symbol ::= is read as "is defined as", meaning the left part of the statement may be replaced with the right part, using transformation rules. Here I simplify and use only two rules: the Alternate-rule uses the pipe char | and says, "choose one of the options offered only"; the Optional-rule uses the curly brackets {} to indicate optional parts. Optional parts may occur once, many times or not at all. All other symbols are so called terminal symbols and have to be written as shown.
<variableBlock> ::= { <simpleVariableDeclaration> ; } <simpleVariableDeclaration>
<simpleVariableDeclaration> ::= <variableName> = <FileMakerExpression>
<condition> ::= true | false | <booleanFileMakerExpression>
<repeatedBlock> ::= <variableBlock>
<resultExpression> ::= <FileMakerExpression>
Since we simplified the syntax description to show just the structure of this very special loop construct, I shortly describe the missing parts in prose. A FileMakerExpression is any valid expression that returns a value. The most simple expression is 1 (with the symbol '1' representing the number one). The value again is the value of the number itself. Or if interpreted as booleanFileMakerExpression it will be seen as true.
Example and Performance
Enough theory. It follows a very simple example that shows the use of the syntax and demonstrates the performance of the new While() construct compared to an equivalent recursive function. Goal is to let the calculation repeat exact 49.999 times and return the time it took to execute. Thus the result of the example is of type number, representing the milliseconds it was running.
While (
// 1. Parameter: variableBlock
[ i = 1 ; imax = 50000; start = Get ( CurrentTimeUTCMilliseconds )] ;
// 2. Parameter: condition
i < imax ;
// 3. Parameter: repeatedBlock
[ i = i + 1 ] ;
// 4. Parameter: resultExpression
Get ( CurrentTimeUTCMilliseconds ) - start & " msecs"
)
The <repeatedBlock> contains only one instruction, incrementing the variable i, declared in the <variableBlock> with 1. As you can see, blocks may always be included between square brackets, it is required to use them if more than one statement is in one block.
Typical execution time on my machine (an elderly Mac mini) is <210 msecs.
Now I built what I assume to be an equivalent recursive construction involving a Custom Function called "WhileByRecursion". On the same machine it takes today ≈ 390 msecs.
// Function: WhileByRekursion (init; startTimeUTCMilliseconds )
//
// call: WhileByRecursion ( 1 ; Get ( CurrentTimeUTCMilliseconds ))
Let ([ init = init + 1;
imax =50000
];
If ( init >= imax;
Get ( CurrentTimeUTCMilliseconds ) - start & " msecs" & ¶ & init ;
// else call me again
WhileByRecursion ( init; start ) )
)
Further experimenting showed that the extra time in case of the custom function stems mostly from the parameter handling when calling the function.
A sample file free to use is available for subscribers of the German FileMaker-Magazin, issue Summer 2019 together with the German version of this post.
The article (in German) can be downloaded here.