Previous Table of Contents Next


6.2.1.7. Procedures

A procedure consists of a sequence of expressions bounded by the reserved words procedure and end. The name of the procedure and its parameters enclosed in parentheses follow procedure. An example is

    procedure max(i, j)

       if i > j then return i else return j

    end

which produces the maximum of i and j. The expression return returns its argument as the value of the procedure call.

A procedure may fail instead of producing a result by using fail instead of return. An example is

    procedure posmax(i, j)
     
       if i > j then {
          if i > 0 then return i else fail
          }
       else if j > 0 then return j else fail

    end

which produces the maximum of i and j provided it is positive but fails otherwise.

Flowing off the end of a procedure without a return also causes the procedure to fail.

Procedures may be called recursively, directly, or through a sequence of other procedure calls. An example is provided by the familiar factorial operation, n! = 1 × 2 × … × n:

    procedure factorial(n)

       if n < 2 then return 1
       else return n * factorial(n – 1)

    end

Procedures are values. That is, they can be assigned to variables, passed as arguments, and so on. Consider

    procedure nonneg(p, n)

       if n < 0 then fail
       else return p(n)

    end

This procedure fails if n is less than zero but otherwise returns the value produced by p(n). For example,

    nonneg(factorial, n)

produces the factorial of n if it is greater than or equal to zero but fails otherwise.

6.2.1.8. Scope

Icon provides three kinds of scope for variables: global, local, and static. Variables have the null value initially, except for global variables that are the names of functions and procedures.

The values of global variables are available to all procedures and for the duration of program execution. Global declarations occur outside procedure declarations. For example,

    global state
    global mode

declares state and mode to be global and available throughout the program.

Local and static variables belong to procedures and are declared inside them. Local variables are created when a procedure is called and destroyed when it returns. For example, in

    procedure revolve(x, y)
       local z
          …

z is local to revolve(). Parameters, in this case x and y, are local, also.

Static variables belong to all calls of the procedure in which they are declared but last throughout program execution and are available to all calls of the procedure. This allows variables to be shared by all calls of a procedure. Static variables can be initialized in an initial expression, which is evaluated only the first time a procedure is called. For example, in

    procedure fracture(s)
       static vowels

       initial vowels :=  “aeiouAEIOU”
            …

the static variable vowels is initialized in the first call of fracture() and that value is available in all subsequent calls of fracture().

6.2.1.9. Input and Output

As indicated by previous examples, read() and write() read and write lines of text, respectively. In the absence of a specified file, read() reads from standard input and write() writes to standard output. Files can be specified, as in

    read(database)
    write(log, entry)

A file is opened by

    open(name, options)

where name is the name of the file and options specifies how it is to be opened. The default option, if the argument is omitted, is opening for reading, as in

    database := open(“backup.db”)

The option “w” opens a file for writing, as in

    log := open(“newlog.txt”, “w”)

The function open() fails if the named file cannot be opened in the specified manner. It is important to check for this, as in

    database := open(“backup.db”) | stop(“*** cannot open backup”)

Note the use of alternation to evaluate another expression if the first one fails. The function stop() is like write(), but it writes its argument to standard error output and terminates program execution.

Three keywords, indicated by an initial ampersand, have values for the standard files:

&input—Standard input
&output—Standard output
&errout—Standard error output

Thus,

    write(&errout, “ ignition failure”)

writes an error message to standard error output but does not terminate program execution like stop() does.

In addition to line-oriented input and output, Icon supports binary input and output and random access to files.

6.2.1.10. Preprocessing

Icon has an integrated preprocessor that allows files to be included, symbols to be defined, and so forth. Preprocessor directives begin with $, as illustrated by

    $include “constants.defs”

which inserts the file constants.def in place of the preprocessor directive. Similarly,

    $define Width 10

defines the constant Width to have the value 10. Subsequently, appearances of Width are replaced by 10.

6.2.1.11. Storage Management

Many values in Icon require storage space in memory; strings and structures are examples. Icon allocates storage for values when they are created. This is done automatically without explicit allocation expressions in the program.

If there is not enough memory to provide space for a newly created value, memory is garbage-collected to reclaim space that no longer is in use. This also is an automatic process and occurs only as needed.


Previous Table of Contents Next