Flow control

Process flow control functions are the functions that execute the decision making and resultant logic branches in executable code. IF–THEN-ELSE, discussed in Chapter 6, Introduction to C/SIDE and C/AL, is also a member of this class of functions. Here we will discuss the following:

  • REPEAT-UNTIL
  • WHILE-DO
  • FOR-TO and FOR-DOWNTO
  • CASE-ELSE
  • WITH-DO
  • QUIT, BREAK, EXIT, and SKIP

REPEAT-UNTIL

REPEAT–UNTIL allows us to create a repetitive code loop which REPEATs a block of code UNTIL a specific conditional expression evaluates to TRUE. In that sense, REPEAT–UNTIL defines a block of code, operating somewhat like the BEGIN–END compound statement structure which we covered in Chapter 6, Introduction to C/SIDE and C/AL. REPEAT tells the system to keep reprocessing the block of code, while UNTIL serves as the exit doorman, checking if the conditions for ending the processing are true. Because the exit condition is not evaluated until the end of the loop, a REPEAT–UNTIL structure will always process at least once through the contained code.

REPEATUNTIL is very important in NAV because it is often part of the data input cycle along with the FIND-NEXT structure, which will be covered shortly.

Here is an example of the REPEATUNTIL structure to process and sum data in the 10-element array CustSales:

LoopCount := 0;
REPEAT
 LoopCount := LoopCount + 1;
 TotCustSales := TotCustSales + CustSales[LoopCount];
UNTIL LoopCount = 10;

WHILE-DO

A WHILEDO control structure allows us to create a repetitive code loop which will DO (execute) a block of code WHILE a specific conditional expression evaluates to TRUE. WHILEDO is different from REPEATUNTIL, both because it may need a BEGIN–END structure to define the block of code to be executed repetitively (REPEATUNTIL does not) and it has different timing for the evaluation of the exit condition.

The syntax of the WHILEDO control structure is as follows:

WHILE <Condition> DO <Statement>

Condition can be any Boolean expression which evaluates to TRUE or FALSE. Statement can be simple or the most complex compound BEGIN–END statement. Most WHILEDO loops will be based on a BEGIN–END block of code. Condition will be evaluated at the beginning of the loop. When it evaluates to FALSE, the loop will terminate. Thus, a WHILEDO loop can be exited without processing.

A WHILE-DO structure to process data in the 10-element array CustSales is as follows:

LoopCount := 0;
WHILE LoopCount < 10
DO BEGIN 
 LoopCount := LoopCount + 1;
 TotCustSales := TotCustSales + CustSales[LoopCount];
END;

In NAV, REPEAT-UNTIL is much more frequently used than WHILE-DO.

FOR-TO or FOR-DOWNTO

The syntax for a FOR-TO or FOR-DOWNTO control statement is as follows:

FOR <Control Variable> := <Start Number> TO <End Number> DO   <Statement>

or

FOR <Control Variable> := <Start Number> DOWNTO <End Number> DO   <Statement>

A FOR control structure is used when we wish to execute a block of code a specific number of times.

The Control Variable is an Integer variable. Start Number is the beginning count for the FOR loop and End Number is the final count for the loop. If we wrote the statement: FOR LoopCount := 5 TO 7 DO [block of code] then [block of code] would be executed 3 times.

FOR-TO increments the Control Variable. FOR-DOWNTO decrements the Control Variable.

We must be careful not to manipulate the Control Variable in the middle of our loop. Doing so will likely yield unpredictable results.

CASE-ELSE statement

The CASEELSE statement is a conditional expression very similar to IF–THEN–ELSE, except that it allows for more than two choices of outcomes for the evaluation of the controlling expression. The syntax of the CASE-ELSE statement is as follows:

CASE <ExpressionToBeEvaluated> OF
  <Value Set 1> : <Action Statement 1>;
  <Value Set 2> : <Action Statement 2>;
  <Value Set 3> : <Action Statement 3>;
  ...
  ...
  <Value Set n> : <Action Statement n>;
 [ELSE <Action Statement n + 1>;
END;

The ExpressionToBeEvaluated must not be a record. The data type of the Value Set must be capable of being automatically converted to the data type of the ExpressionToBeEvaluated. Each Value Set must be an expression, a set of values, or a range of values. The following example illustrates a typical instance of a CASE-ELSE statement:

 CASE Customer."Salesperson Code" OF
   '2','5','9': Customer."Territory Code" := 'EAST';
   '16'..'20': Customer."Territory Code" := 'WEST';
   'N': Customer."Territory Code" := 'NORTH';
   '27'..'38': Customer."Territory Code" := 'SOUTH';
  ELSE Customer."Territory Code" := 'FOREIGN';
 END;

In the preceding example, we see several alternatives for the Value Set. The first line (EAST) Value Set contains the list of values. If Salesperson Code is equal to '2', '5', or '9', the value EAST will be assigned to Customer."Territory Code". The second line (WEST) Value Set is a range, any value from '16' through '20'. The third line (NORTH) Value Set is just a single value ('N'). If we look through standard NAV code, we will see that a single value is the most frequently used CASE structure in NAV. In the fourth line of our example (SOUTH), the Value Set is again a range ('27'..'38'). If nothing in any Value Set matches ExpressionToBeEvaluated, the ELSE clause will be executed.

An example of an IF-THEN-ELSE statement equivalent to the preceding CASE-ELSE statement is as follows:

 IF Customer."Salesperson Code" IN ['2','5','9'] THEN 
  Customer."Territory Code" := 'EAST'
   ELSE IF Customer."Salesperson Code" IN ['16'..'20'] THEN 
     Customer."Territory Code" := 'WEST'
    ELSE IF Customer."Salesperson Code" = 'N' THEN 
      Customer."Territory Code" := 'NORTH'
     ELSE IF Customer."Salesperson Code" IN ['27'..'38'] THEN 
       Customer."Territory Code" := 'SOUTH'
      ELSE Customer."Territory Code" := 'FOREIGN';

The following is a slightly less intuitive example of the CASEELSE statement. In this instance, ExpressionToBeEvaluated is a simple TRUE and the Value Set statements are all conditional expressions. The first line containing a Value Set expression that evaluates to TRUE will be the line whose Action Statement is executed. The rules of execution and flow in this instance are same as in the previous example.

 CASE TRUE OF Salesline.Quantity < 0:
  BEGIN
   CLEAR(Salesline."Line Discount %");
   CredTot := CredTot - Salesline.Quantity;
  END;
   Salesline.Quantity > QtyBreak[1]: 
    Salesline."Line Discount %" := DiscLevel[1];
   Salesline.Quantity > QtyBreak[2]: 
    Salesline."Line Discount %" := DiscLevel[2];
   Salesline.Quantity > QtyBreak[3]: 
    Salesline."Line Discount %" := DiscLevel[3];
   Salesline.Quantity > QtyBreak[4]: 
    Salesline."Line Discount %" := DiscLevel[4];
  ELSE
   CLEAR(Salesline."Line Discount %");
 END;

WITH-DO statement

When we are writing code referring to fields within a record, the most specific syntax for field references is the fully qualified reference [ RecordName.FieldName ]. When referring to the field City in the record Customer, use the reference Customer.City.

In many C/AL instances, the record name qualifier is implicit, because the compiler assumes a default record qualifier based on the code context. This happens automatically for variables within a page bounded to a table. The bound table becomes the implicit record qualifier for fields referenced in the Page object. In a Table object, the table is the implicit record qualifier for fields referenced in the C/AL in that object. In Report and XMLport objects, the Data Item record is the implicit record qualifier for the fields referenced within the triggers of that Data Item such as OnAfterGetRecord and OnAfterImportRecord.

In all other C/AL code, the only way to have an implicit record qualifier is to use the WITH-DO statement. WITH-DO is widely used in the base product in Codeunits and processing Reports. The WITH-DO syntax is:

WITH <RecordQualifier> DO <Statement>

Typically, the DO portion of this statement will be followed by a BEGIN-END code block, allowing for a compound statement. The scope of the WITH-DO statement is terminated by the end of the DO statement.

When we execute a WITH-DO statement, RecordQualifier becomes the implicit record qualifier used by the compiler until the end of that statement or until that qualifier is overridden by a nested WITH-DO statement. Where fully qualified, syntax would requires the following form:

Customer.Address := '189 Maple Avenue';
Customer.City := 'Chicago';

The WITH-DO syntax takes advantage of the implicit record qualification making the code easier to write, and hopefully easier to read. For example:

WITH Customer DO
BEGIN 
 Address := '189 Maple Avenue';
 City := 'Chicago';
END;

Best practice says that WITH-DO statements should only be used in functions within a Codeunit or a Report.

WITH-DO statements nested one within another are legal code, but are not used in standard NAV. They are also not recommended because they can easily confuse the developer, resulting in bugs. The same comments apply to nesting a WITH-DO statement within a function where there is an automatic implicit record qualifier, such as in a table, Report, or XMLport.

Of course, wherever the references to record variables other than the implicit one occur within the scope of a WITH-DO statement, we must include the specific qualifiers. This is particularly important when there are variables with the same name (for example, City) in multiple tables that might be referenced in the same set of C/AL logic.

Some developers maintain that it is always better to use fully qualified variable names to reduce the possibility of inadvertent reference errors. This approach also eliminates any possible misinterpretation of variable references by a maintenance developer who works on this code later.

QUIT, BREAK, EXIT, and SKIP functions

This group of C/AL functions also control process flow. Each acts to interrupt flow in different places and with different results. To get a full appreciation for how these functions are used, we need to review them in the correct place in code in NAV 2015.

QUIT function

The QUIT function is the ultimate processing interrupt for Report or XMLport objects. When a QUIT is executed, processing immediately terminates even for the OnPostObject triggers. No database changes are committed. QUIT is often used in reports to terminate processing when the report logic determines that no useful output will be generated by further processing.

The syntax of the QUIT function is as follows:

CurrReport.QUIT;
CurrXMLport.QUIT;

BREAK function

The BREAK function terminates the DataItem in which it occurs. BREAK can only be used in Data Item triggers in Reports and XMLports. It can be used to terminate the sequence of processing one DataItem segment of a report while allowing subsequent DataItem processing to continue.

The BREAK syntax is one of the following:

CurrReport.BREAK;
CurrXMLport.BREAK;

EXIT function

EXIT is used to end the processing within a C/AL trigger. EXIT works the same whether it is executed within a loop or not. It can be used to end the processing of the trigger or to pass a return value from a local function. A return value cannot be used for system defined triggers or local functions that don't have a return value defined. If EXIT is used without a return value, a default return value of zero is returned. The syntax for EXIT is:

EXIT([<ReturnValue>])

SKIP function

When executed, the SKIP function will skip the remainder of the processing in the current record cycle of the current trigger. Unlike BREAK, it does not terminate the DataItem processing completely. It can be used only in the OnAfterGetRecord trigger of a Report or XMLport object. In reports, when the results of processing in the OnAfterGetRecord trigger are determined not to be useful for the output, the SKIP function is used to terminate that single iteration of the trigger without interfering with any subsequent processing.

The SKIP syntax is one of the following:

CurrReport.SKIP;
CurrXMLport.SKIP;
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.86.149