17.2 Flow Control

XploRe offers a variety of possibilities to implement sophisticated structures in your programs. With the commands introduced in the following you are able to make your program react on conditions; you can handle failures while avoiding or provoking a program's stop, and last but not least, you can give your program a well-structured, understandable shape.


17.2.1 Local and Global Variables


39444 putglobal (x)
generates a global variable x
39447 getglobal (x)
reads a global variable x
39450 existglobal ("x")
checks the existence of a global variable x

When you are working with procedures, you have to know whether the variables used in the procedures are accessible in the main program and vice versa. The answer is: XploRe strictly distinguishes between globally and locally defined variables.

Variables in procedures can take on the values of global ones. The procedure then can use the values, change them, and compute various results, but it cannot change the value of the original global variable. However, XploRe helps you to overcome this restriction by using the 39461 putglobal and 39464 getglobal commands. Note that these as well as the 39467 existglobal only work within procedures.

XploRe offers you the possibility to easily transfer a variable from the procedure to the main program. A locally defined variable can then (when the procedure has been run at least once) be accessed and changed in the main program.

Consider the following example:

  proc() = test(a, b) 
    c = a + b       ; computes c as the sum of a and b, 
                    ;    c is now a local variable
    putglobal("c")  ; declares c to be also GLOBAL variable
  endp               
 
  x = 1
  y = 2

  test(x, y)        ; runs the procedure test taking the 
                    ;    values of the globals x and y for 
                    ;    the locals a and b

  c                 ; output of c, c is accessible here 
                    ;    because it has been transferred by 
                    ;    the putglobal command
39475 XLGquant07.xpl

It produces the following output
  Contents of c
  [1,]    3

You can also do this the other way around. Normally in a procedure it is not possible to access global variables with the exception of those transferred in the head of the procedure's definition.

For this purpose, you use the 39480 getglobal command, which can transfer the value of a global variable to a local variable. The value can then be used, changed, and results can be computed in the procedure. However, it will not change the global variable in the main program.

  proc() = test(a, b)  
    z = getglobal("z") ; the local z takes on the value of 
                       ;    the global z
    z = a +b +z        ; computes the local z as a sum
    z                  ; output of the "local" z
  endp                 

  x = 1
  y = 2
  z = 3

  test(x, y)           ; runs the procedure test with the 
                       ;    values of x and y for the locals 
                       ;    a and b, respectively, prints the
                       ;    local z

  z                    ; prints the global z
39484 XLGquant08.xpl

You obtain this result:
  Contents of z
  [1,]    6
  Contents of z
  [1,]    3
We want to remark here that the existence of a global variable can be checked by 39489 existglobal .


17.2.2 Conditioning


39585 if - { 39588 else } - 39591 endif
conditional branching with two branches

In XploRe , you have the possibility to let the execution of one or several commands depend on a logical condition. XploRe is able to check whether a certain condition is fulfilled or not and then executes the relevant commands in either case. Note that the 39602 if - 39605 else - 39608 endif construct only works within procedures.

For example: To compute the square root of a number, you have to make sure that the number is not negative. To this aim it is advisable to use the following 39611 if - 39614 else - 39617 endif construction:

  proc() = squareroot(a)   
    if(a >= 0)         ; if this condition is true, 
                       ;    XploRe will execute the next 
                       ;    commandline

      sqrt(a)          ; computes the squareroot of a
    else               ;   in case the condition above is not 
                       ;   fulfilled XploRe runs the else branch
      "number is negative"   
                       ; output of the else branch
    endif              ; end of the if construction

  endp                 ; end of the procedure
39621 XLGquant09.xpl

You can check the effect if you call this procedure with a negative argument, e.g.

 
  squareroot(-10)      ; runs the procedure with value -10
You obtain the following output:
  Contents of _tmp
  [1,]"number is negative"

By running the procedure squareroot with a positive argument

  squareroot(9)        ; runs the procedure with value 9
you obtain the desired result
  Contents of sqrt
  [1,]    3
Note that the 39626 else branch is optional.


17.2.3 Branching


39720 switch - 39723 case (x) - 39726 endsw
conditional branching with more than two branches
39729 break
marks the end of a case block inside the switch environment, the procedure is continued at endsw; it can be omitted
39732 default
when the program's counter comes inside a 39735 switch - 39738 endsw construct to this keyword, the following commands are processed in any case; a default statement can be finished by the keyword break, but does not have to be

If you want to make more than two branching points within your program, you may use the 39741 switch - 39744 case - 39747 endsw construction.

The following procedure can distinguish whether its argument is positive, negative or zero:

  proc() = signum(x)       ; defines a procedure named "signum"

    switch                 ; opens the switch branch
      case (x > 0) 
        "positive number"  ; output in the case that x > 0
        break 
      case (x < 0) 
        "negative number"  ; output in the case that x < 0
        break                   
      default
        "number is zero"   ; output in the case that x = 0
        break
    endsw                  ; end of the switch branch
  endp                     ; end of the procedure
39751 XLGquant10.xpl

By calling it with different arguments

  signum(10)               ; runs the procedure with value 10
  signum(-5)               ; runs the procedure with value -5
  signum(0)                ; runs the procedure with value 0
you obtain, respectively, the following results
  Contents of _tmp
  [1,]"positive number"
  Contents of _tmp
  [1,]"negative number"
  Contents of _tmp
  [1,]"number is zero"


17.2.4 While-Loop


39831 while - 39834 endo
repeats one or several commands as long as some condition is fulfilled

You may execute one or several commands repeatedly -- as long as a certain condition is fulfilled. For this purpose you have the 39837 while - 39840 endo loop at your disposal. Note that the 39843 while - 39846 endo construct only works within procedures.

This kind of loop executes one or several commands as long as a logical condition is fulfilled. The following example explains how the factorial of a natural number can be computed using this loop:

  proc(j) = factorial(x) 
                    ; defines a procedure named "factorial"
    j = 1           ; defines the variable j as 1

    while (x >= 2)  ; as long as this condition is fulfilled, 
                    ;    XploRe executes the following commands

      j = j * x     ; computes j as the product of j and x
      x = x - 1     ; reduces x by 1
    endo            ; end of the while loop
  endp              ; end of the procedure
39850 XLGquant11.xpl

After calling the procedure with command
  factorial(5)      ; runs the procedure with value 5
you obtain the factorial $ 5!$ calculated with the help of the 39855 while - 39858 endo loop:
  Contents of j
  [1,]    120


17.2.5 Do-Loop


39928 do - 39931 until
repeats one or several commands until the condition is fulfilled

Another possibility for looping inside XploRe procedures is provided by the
[3]39938 do - 39941 until construction. As with the 39944 while - 39947 endo construct, the 39950 do - 39953 until works only within procedures.

In contrast to the 39956 while - 39959 endo loop, the 39962 do - 39965 until loop executes one or several commands until a certain condition is fulfilled. Since the condition will be checked at the end of the loop, it runs at least once. An example follows:

  proc(j) = factorial(x) ; defines a procedure named "factorial"
    j = 1                ; defines the variable j as 1
    do                   ; opens the do loop
      j = j *x           ; computes j as the product of j and x  
      x = x -1           ; reduces x by 1
    until (x < 2)        ; if the condition is not fulfilled, 
                         ;    the loop will be run again
  endp                   ; end of the procedure
39969 XLGquant12.xpl

Calling the procedure with argument 5

  factorial(5)      ; runs the procedure with value 5
produces the desired result:
  Contents of j
  [1,]    120


17.2.6 Optional Input and Output in Procedures


40104 exist ("x") or 40107 exist (x)
checks the existence and the type of a variable x

Both the input and output parameters of a procedure quantlet are in fact lists. For more information on lists, see Matrix Handling (16).

Due to this list concept, all input and output parameters can be optional. The existence of input parameters can be checked with the 40110 exist command. Table 17.1 gives all possible return values for 40113 exist .


Table: Return values of 40116 exist .
Value Meaning
-1 object does not exist
0 object exists but is empty
1 object exists and is numeric
2 object exists and is text
3 object exists and is of type XPLTIME
4 object exists and is a display
9 object exists and is a composed object (list)
10 object exists and is a quantlet
$ >$ 10 object exists as a quantlet and a variable, e.g. if there is a numeric variable cov and the library("xplore") is loaded exist("cov") results in 11


Consider the following example:

  proc(a,b)=myquant3(x,y)
    error(exist("x")<>1, "input x is not numeric!")
    if (exist("y")==0) ; y does not exist
      y=0
    endif

    switch
      case (exist("y")==2) ; if y is a string
        a=x
        break
      case (exist("y")==1) ; if y is numeric
        a=x
        b=y
        break
      default;
        error(1, "y is neither numeric nor string!")
        break
    endsw
  endp
40120 XLGquant13.xpl

The quantlet myquant3 checks first, whether the input x is numeric. Then the existence of y is checked. If y does not exist, it is set to the numeric value 0.

The switch environment produces different results for the cases that y is string or numeric, respectively. We added an error message for the case that y is neither string nor numeric. You may now test the procedure with different input values:

  result=myquant3(1,2)
  result
gives
  Contents of result.a
  [1,]        1 
  Contents of result.b
  [1,]        2
This means that the resulting output object is a list comprising the components result.a and result.b, which contain just the input values.

We can also call myquant3 without specifying the input y, i.e.

  result=myquant3(1)
  result
The result is similar, except that the missing y value is replaced by 0:
  Contents of result.a
  [1,]        1 
  Contents of result.b
  [1,]        0

In the case that a string input y is used, the result is again different:

  result=myquant3(1,"hallo")
  result
produces only one output
  Contents of result.a  
  [1,]        1

To be on the safe side, we assign the output always to the same variable result. This captures the case of two outputs as well as of one output. The function 40125 exist can be used again to check whether the output variable result contains valid component result.b. For our last example

  exist(result.b)
yields
  Contents of exist
  [1,]        0
which indicates that the component result.b is empty.


17.2.7 Errors and Warnings


40294 error (cond, message)
stops a XploRe program and displays a message
40297 warning (cond, message)
displays a warning message

You have the opportunity to give to the user some hints about problems which occurred when the program is run. With the 40300 error and 40303 warning commands, you can transmit messages to the user of the program.

Both commands check whether a certain condition is true (equal to 1) or not (equal to 0). If the condition is true, a window will be displayed containing a message that has been specified within the command. If the condition is false, the program continues with the next command.

The 40306 error command displays the error box and stops immediately if the given condition is fulfilled. All data and changes to variables that have not been saved before this moment will be lost.

  proc() = test(x)   ; defines a procedure
    error(x<0,"Negative argument!") 
                     ; displays an error box containing the 
                     ;    specified text and stops the program 
                     ;    in case x is negative
    sqrt(x)          ; computes the square root in case the 
                     ;    preceding command did not lead to
                     ;    a break of the program
  endp               ; end of the procedure
40310 XLGquant14.xpl

Calling this procedure with the negative argument
  test(-4)           ; runs the procedure with value -4
will display only this error message:

40316

If you do not want to stop the program immediately after checking a problem, you can use the 40318 warning command. In this case there is no data loss. If the condition in the 40321 warning command is fulfilled, the program continues and shows a warning box after it finishes:

  proc() = test(x)   ; defines a procedure

    warning(x<0,"Negative argument!") 
                     ; displays a warning box containing the
                     ;    specified text in case x is 
                     ;    negative at the end of the program 

    sqrt(abs(x))     ; computes the squareroot of abs(x), 
                     ;    whatever the above command found 
                     ;    about x

  endp               ; end of the procedure
40325 XLGquant15.xpl

Calling this procedure with the negative argument
  test(-9)           ; runs the procedure with value -9
will produce the result
  Contents of sqrt
  [1,]    3
accompanied with the warning

40331