|  |  3.8.6 Procedures in a library 
Here asre hints and requirements on how procedures contained in a
library should be implemented. For more on procedures,
see  Procedures.
 
Each procedure not meant to be accessible by users should be declared static.
The header of each procedure not declared static must comply with the guidelines
described in  Procedure definition and  Help string.
In particular, it must have a help and example section, and assumptions made
should be carefully explained. If the assumptions are checked by the procedure
on run-time, errors may be reported using the  ERROR function.
Names of procedures should not be shorter than 4 characters and should not
contain any special characters. In particular, the use of _in names of
procedures is discouraged. If the name of the procedure is composed of
more than one word, each new word should start with a capital letter, all
other letters should be lower case (e.g. linearMapKernel).
No procedures should be defined within the body of another procedure.
A procedure may print out comments, for instance to explain results or to
display intermediate computations. This is often helpful when calling the
procedure directly, but it may also cause confusions in cases where the
procedure is called by another procedure. The SINGULAR  solution to
this problem makes use of the function dbprint(see  dbprint)
and the reserved variablesprintlevelandvoice(see  printlevel and see  voice). Note thatprintlevelis a
predefined, global variable whose value can be changed by the user, whilevoiceis an internal variable, representing the nesting level of
procedures. Accordingly, the value of  voice is 1 on the top level,
2 inside the first procedure, and so on. The default value ofprintlevelis 0, butprintlevelcan be set to
any integer value by the user. 
 
Example:
If the procedure Testbelow is called directly from
the top level, then `comment1' is displayed, but not `comment2'.
By default, nothing is displayed ifTestis called from within any
other procedure. However, ifprintlevelis set to a value k
with k>0, then `comment1' (resp. `comment2') is displayed -- providedTestis called from another procedure with nesting level at
most k (resp. k-1).
The example part of a procedure behaves in this respect like the
procedure on top level (the nesting level is 1, that is, the value of
voiceis 2). Therefore, due to the commandprintlevel=1;,
`comment1' will be displayed when enteringexample Test;.
However, since printlevel is a global variable, it should be reset to
its old value at the end of the example part. 
The predefined variable echocontrols whether input lines are
echoed or not. Its default is 0, but it can be reset by the user. Input
is echoed ifecho>=voice. At the beginning of the example
part,echois set to the value 2. In this way, the input lines
of the example will be displayed when enteringexample Test;. 
 |  |       proc Test
      "USAGE:   ...
               ...
      EXAMPLE: example Test; shows an example
      "
      {   ...
         int p = printlevel - voice + 3;
          ...
         dbprint(p,"comment1");
         dbprint(p-1,"comment2");
         // dbprint prints only if p > 0
          ...
      }
      example
      { "EXAMPLE:"; echo = 2;
         int p = printlevel;   //store old value of printlevel
         printlevel = 1;       //assign new value to printlevel
          ...
         Test();
         printlevel = p;       //reset printlevel to old value
      }
 | 
 
Note:
SINGULAR  functions such as pauseorreadallow
and require interactive user-input. They are, thus, in particular useful
for debugging purposes. If such a command is used inside the procedure
of a library to be distributed with SINGULAR, the example section of
the procedure has to be written with some care -- the procedure should
only be called from within the example if the value ofprintlevelis 0. Otherwise,  the automatic build process of SINGULAR will not
run through since the examples are carried out during the build process.
They are, thus, tested against changes in the code. 
 |