For-loops
Last updated
Last updated
Using the @for
and @for-calc
functions, you can generate a list of items (snippets of text, numbers, dates, …) by iterating through another list of values. Programmers will be very familiar with this idea, as for-loops are essential ingredients of most programming languages. For legal professionals, this idea will sound much more abstract — we will therefore explain the idea through relevant examples.
When using @for
and @for-calc
, you have to specify three different parameters: a placeholder, a list of elements to iterate (“loop”) with, and an internal snippet that will be used in each iteration. For example,
This code will loop through the bottom snippet three different times, each time replacing the placeholder ?X
with the next element of the list. Accordingly, the result will be a list of texts containing “this is element alpha”, “this is element beta” and “this is element gamma”. You can then use this resulting list in any way possible, for example convert it into bullets using @bullets( ... )
or into an inline-enumeration using @enumerate
.
The difference between @for
and @for-calc
is that @for
will always resulting in a list of text snippets (i.e., a word, a part of a sentence, or even entire paragraphs), while @for-calc
will result in a list of values, whereby each value must be a whole/floating number, a currency value, a duration, undefined, or a list itself. If @for-calc
cannot extract such value (e.g., because the intermediate result is a text snippet), then it will result in an error.
In addition to the placeholder you specify yourself (?X
in the example above), the software will also allow you to use the following implicit placeholders:
?INDEX
will contain the current iteration number, starting from 1 and increased with each iteration.
?MAX-INDEX
will contain the total number of iterations that will be performed. Note that this value will remain constant throughout all iterations.
?PREVIOUS
will contain the result of the previous iteration
?ACC
(for “accumulator”) will contain the list of results up to (but not yet including) the current iteration
In the example below, three iterations are shown, whereby ?X
will be assigned the value 10, 11 and 12 respectively, while the ?INDEX
will be assigned the value 1, 2 and 3 respectively. Note that the ?PREVIOUS
value will not contain a value in the first iteration (for obvious reasons). In the second iteration, it will contain the bullet that resulted from the previous iteration; in the third iteration, it will contain the bullet of the first iteration, as well as the sub-bullet of the second iteration. The example in the screenshot below is contrived, but you will see in the real examples below how the ?PREVIOUS
value can be used.
In a loan agreement, we want to create a list of bullets that contains an overview of all the monthly repayment dates, starting from a certain commencement. The parameters of the loan are saved into the datafields loan^start-date
, #loan^frequency
(a duration — e.g., one month or 2 weeks) and #loan^instalments
(the number of repayments, e.g. 5).
Using a for-loop, we could then write:
In human language, this roughly means the following:
create a list (range) of items, starting from 1, up to (but including) the number of instalments — e.g. from 1 to 5
create a resulting list in memory, that will hold all the intermediate results
do the following 5 times:
set placeholder ?INSTALMENT-NR
to the current item (i.e., the first time set it to 1, the next time to 2, etc.)
take internal snippet @BULLET
, and replace placeholder ?INSTALMENT-NR
with its current value
put the intermediate result into the resulting list
take the resulting list, and convert it into bullets.
The results can be seen in the following screenshot, when using the focus mode. You are strongly recommended to use this focus mode, because it allows you to interactively experiment with the for-loops.
Let’s assume that in a rental agreement you need to show the indexed rent amount over a certain period. For example, with a starting amount 1000 EUR and a yearly indexation of 5%, you may be tempted to write the following:
Unfortunately, this is not how most real-world indexation clauses work, as the indexation should take the then-applicable amount as the starting point each time. This can be solved using the ?PREVIOUS
placeholder. In the example below, we use @for-calc
to calculate a list of all rental amounts, which is then shown in another @for
-loop. (The reason being that a @for
loop results in a piece of text, that cannot be used in further mathematical calculations):
The AMOUNT
snippet essentially says “if no previous value exists (i.e., we are at the first iteration), then simply use the base amount; however, if a previous value exists (which should be the case as from the second iteration), then use the previous value and apply the indexation to it”.
Note that we use curly braces around the result in the AMOUNT
snippet in order to force the result to become a number. If you leave these curly braces, you immediately get errors, because the software would then treat the result of that snippet as a piece of text, while@for-calc
can only work with a number / currency value / duration / list / undefined value.
As another example, let’s assume that a contract wants to show a table that illustrates how an amount of 1000 EUR is paid back over five months. The calculation per period is deliberately kept very simple, but the idea is clear that you could also use the various types of mortgage payment calculations here.
What we’re doing here, essentially, is to construct a table that consists of six different rows (a header row, and one row per repayment-period), merged together using @merge-tables
. Each repayment period’s row then contains a cell with the calculated date, the amount (in the example always 200), and then a cell with the remaining value. The remaining value is extracted using @get
from a list of repayment amounts that is generated by the @AMOUNTS-LIST
snippet, which uses a simple @for-calc
loop.
Note that when the loan amount, number of periods, starting date, etc. are placed in datafields, this kind of table can even be interactively shown within a Q&A, allowing end-users to experiment with these values.
Particularly interesting in the focus mode is its ability to isolate a particular snippet. For example, when you isolate snippet @BULLET
, and then assign values to the ?INSTALMENT-NR
placeholder through the button, you can interactively “step through” each iteration. (Programmers sometimes call this “debugging”, i.e. a mode dedicated to removing potential “bugs” from their software code).