Sage-Code Laboratory
index<--

Bee Control Flow

Control flow statements are used to alter the linear program workflow. In Bee each control statement start with a different keyword, and ends with one of: done, cycle or next keywords.

Bookmarks

Bee has 7 control statements:

Name Description
do start a block statement
when single or multi-path decision
cycle repetitive unconditional block
while repetitive conditional block
given repetitive block with local scope
check multi-path value selector
trial exception handler block

do-block

Keyword "do" establish a local scope. In this scope you can define variables and functions that will clear out after "done". It is a good idea to separate your concerns of a large business rule by using multiple "do" statements.

Pattern:

Next syntax pattern show the anonynous "do" block.

# anonymous block
do
  // statements
  ...
done; 
Warning: This control statement is anonymous, unconditional and prime. You can not use conditional "if" after "done". Next we are going to explain how to create more intresting "do" blocks that can end with other keywords.

when

This keyword start a conditional branching statement. It create a program branch unsing a condition. In other languages this statement is known as the "if" statement. We also use the "if" keyword but in a different way. We know this is unusual but our decision choices are disruptive. Try to learn our new way and give it a chanse.

decision

decision diagram

Pattern:

The most common syntax pattern is using two branches and one single condition:

# decision with two branches
when condition do
  ** true branch
  ...
else
  ** false branch
  ...
done;

Nesting:

You can use multiple conditions to create nested decisions:

#nested decisions
do
    make a ∈ Z : random(); //control variable
    when a ≤ 0 do
        write "a = ";
        read  a;
        when a = 0 do
            print "a = 0";
        else
            print "a < 0";
        done; //a ≤ 0
    done;
done;    

Ladder

By using keyword "else" and conditional "if" you can create a cascade of decisions called "decision ladder" that has several branches plus one default and optional branch that is executed when no condition is fulfilled.

decision

decision ladder

Example:

# Decision ladder
do
    make a ∈ Z; //control variable
    read("a = ", a);
    when a = 0 do      // first decision  
        print "a = 0";
    orif a > 0 do  // second decision
        print "a > 0";
    orif a < 0 do    // third decision
        print "a < 1";  
    else                  
        print "unexpected:" + a;// unexpected value
    done; 
done;    

Cycle

You can use "cycle" to create a repetitive block. This keyword is used at the end of anonymous block "do" to repeat all statements in the block until a condition can end the cycle. If no condition exist, the cycle is infinite.

Pattern 1: Infinite cycle

Next example show a repetitive "do" block that runs forever. It is not very practical but will be terminated when reaches maxim limit of iteration establish by $iteration variable.

cycle

cycle diagram

#repetitive block
do
  // statements
  ...
cycle;

Pattern 2: run condition

Next block will execute multiple times as long as runCondition is fulfilled.

do-cycle

do-cycle diagram

#cycle conditional
do
  // repetitive block
  ...
cycle if runCondition;

While cycle

Keyword "while" can establish a repetitive block. The number of repetitions is established by a start condition. If a start condition is not fulfilled the finalization block is executed.

while cycle

While Cycle


while startCondition do
    //repetitive statements
    ...
else
    //finalization block
    ...     
cycle;

Given Cycle

You can start a repetitive block by using keyword "given". In other languages you may be using "for". This is our way of making a limited cycle, to visit elements of a range or collection. The range syntax: (min..max:rate) should be known to you from first article about syntax.

given

Given cycle diagram

#visitor pattern
given cv <- (min..max:rate) do
  ** first block
  ...  
  loop if condition; //fast forward
  ** second block
  ...  
  stop if condition; //early transfer
  ** third block
  ...
next;

Notes:

Example 1:

#range iteration with rate 1
given i <- (1..10) do
  when i % 2 = 0 do
    loop;    //rerun fron the beginning
  else
    write i; //odd numbers
  done;
  write ',' if (i < 10);
next;
1,3,5,7,9

Example 2:

Ratio: Using domain ratio the example above can be simplified:

#range iteration with rate 2
given i <- (1..9:2) do
  write(i); //odd numbers
  write(',') if (i < 9);
next;
print;

Notes:

Check

This is a multi-path selector similar also named: jump table..

switch

Check Diagram

Pattern:

#check selector syntax
check x [all | one]
    match v1 do
        //first path
    match v2 do
        // second path
    match (v1, v2, v3) do
        // other path
        ...
    none
        //default path
done;

Example:

Using cycle with nested check selector:

#local scope demo with nested cycle and check
do  
**  local non repetitive scope
    make a ∈ N; 
    given b <- (1..10) do
        // repetitive scope
        alter a := random(0..20);
        print " a = " + a;
        check a one
            match 0 do
                print ("a = 0");
            match (1,3,5,7,9) do
                print "a is odd";
            match (2,4,6,8) do
                print "a is even";
            none
                print ("random: a = " + a);
        done;
    cycle;
done;    

Trial

The trial is by far the most complex statement of Bee language. A trial block is used to handle a process that can have exceptions. It has a default block and optional can include multiple case regions. Each case can resolve one or a list of error. You have options to retry, fail or pass each case.

trial

Trial Diagram

Notes:

Keywords:

Next keywords are used to create a full trial block:

worddescription
trialstart a series of cases
case catch errors with specific code or code range
othercatch all other errors not fixed by a patch
finalfinalization region, executed before trial end
done ending a trial block

Pattern:

#complex trial with many cases
trial
    ** initial or default statements
        ...
    ** early exit without error    
    pass if condition;
        ...
    //optional raise error    
    fail {code, message} if condition; 
    ...
    //optional repeat trial    
    retry if condition;     
case @error.code = code do
    ** handler1
    ...
    pass; //optional stop the trial
case @error.code ∈ (code1,code2) do
    ** handler2
    ...
    retry; //optional repeat trial
other
    ** cover all other errors
    ...
    raise @error if condition; //propagate last error
final
    ** finalization statement (executed before leaving)
    ** not executed when loop but: fail, raise or stop will
    print "final error:" + @error.code if @error.code > 0;
done;

Note:

Errors

Errors can be defined in your program using next notation:

** define error
make error_name := {code,"message"} ∈ Error;

Errors can be issued using "fail" keyword.

** "raise" can create a customized error or message
fail error_name  if condition //create an error that is predefined
fail @error      if condition //propagate last error if is not empty
fail "message"   if condition //create instant user error: 3
fail {code,"message"} //create instant custome error with code

Note: The standard module will define standard error objects as system constants:

case This region can catch an error and resolve. Error can be catched by code or a list of codes. After cases the "final" region is executed but only if the error handler does not do not retry:

Transfer Statements

Next statements are transfer statements used in trial block:

word description
fail transfer execution to cases to resolve an error
pass transfer execution to finalizer and silently terminate the trial block
retry repeat the trial, equivalent to "loop" but usable only in trial blocks

other

This region is used for any other error that is not handled by case handlers. You can use any selector in this region to find an exceptions by code but you can also just report the error or log the error and stop the trial.

final

This region is executed just vefire trial is dobe, regardless of error status. Even if there is no error to propagate this region is still executed.

It can contain:

Example:

#simple trial block
make  x ∈ Q;
make  y ∈ Q;
trial
    alter x := 1/0;
final
    print "x = " + x;
    print @error.message if @error.code ≠ 0;
done;

Fail:

In this example we use "fail" statement to create an error on purpose:

#define a custom error
make my_error := {201, "my error"} ∈ E;
trial
  fail my_error; //issue custom error
case @error.code == 201
  ** we catch the the error and do something
  print @error.message;
  print @error.line;
other
  fail @error; // propagate all errors
done;

Notes:

Retry:

By using "retry"  you can repeat a trial several times until other ending statement is encounter: {pass, fail}. You can issue "retry" from trial block using a condition or from case blocks for specific errors.

#example of repeating trial
make count ∈ (1..3);
make a ∈ (0..9);
** try maximum 3 times
trial
    alter count += 1;
    read a;
    fail if a < 0; //trigger patch     
    when  a < 9 do
      write "correct";    
    orif  a > 9 do    
      write "incorrect";
    done;  
case $out_of_range do
    when count < 3 do
      write "wrong try again:"
      retry; //try again the entire trial
    else
      write "wrong 3 times!";      
      fail $out_of_range;
    done;
final
    print;
done;

Note:


Read next: Rules