Sophie

Sophie

distrib > Mandriva > 8.2 > i586 > by-pkgid > 2f23fa33dbe9052d0cf09567f1224d7c > files > 186

slang-doc-1.4.4-3mdk.i586.rpm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
 <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
 <TITLE> A Guide to the S-Lang Language: Functions</TITLE>
 <LINK HREF="slang-10.html" REL=next>
 <LINK HREF="slang-8.html" REL=previous>
 <LINK HREF="slang.html#toc9" REL=contents>
</HEAD>
<BODY>
<A HREF="slang-10.html">Next</A>
<A HREF="slang-8.html">Previous</A>
<A HREF="slang.html#toc9">Contents</A>
<HR>
<H2><A NAME="s9">9. Functions</A></H2>

<P> 
<P>A function may be thought of as a group of statements that work
together to perform a computation.  While there are no imposed
limits upon the number statements that may occur within a function,
it is considered poor programming practice if a function contains
many statements. This notion stems from the belief that a function
should have a simple, well defined purpose.
<P>
<H2><A NAME="ss9.1">9.1 Declaring Functions</A>
</H2>

<P> 
<P>Like variables, functions must be declared before they can be used. The
<CODE>define</CODE> keyword is used for this purpose.  For example,
<BLOCKQUOTE><CODE>
<PRE>
      define factorial ();
</PRE>
</CODE></BLOCKQUOTE>

is sufficient to declare a function named <CODE>factorial</CODE>.  Unlike
the <CODE>variable</CODE> keyword used for declaring variables, the
<CODE>define</CODE> keyword does not accept a list of names.  
<P>Usually, the above form is used only for recursive functions.  In
most cases, the function name is almost always followed by a
parameter list and the body of the function:
<BLOCKQUOTE><CODE>
define <EM>function-name</EM> (<EM>parameter-list</EM>)
{
<EM>statement-list</EM>
}
</CODE></BLOCKQUOTE>

The <EM>function-name</EM> is an identifier and must conform to the
naming scheme for identifiers discussed in chapter ???.
The <EM>parameter-list</EM> is a comma-separated list of variable names
that represent parameters passed to the function, and
may be empty if no parameters are to be passed.
The body of the function is enclosed in braces and consists of zero
or more statements (<EM>statement-list</EM>).
<P>The variables in the <EM>parameter-list</EM> are implicitly declared,
thus, there is no need to declare them via a variable declaration
statement.  In fact any attempt to do so will result in a syntax
error.
<P>
<P>
<H2><A NAME="ss9.2">9.2 Parameter Passing Mechanism</A>
</H2>

<P> 
<P>Parameters to a function are always passed by value and never by
reference.  To see what this means, consider
<BLOCKQUOTE><CODE>
<PRE>
     define add_10 (a) 
     {
        a = a + 10;
     }
     variable b = 0;
     add_10 (b);
</PRE>
</CODE></BLOCKQUOTE>

Here a function <CODE>add_10</CODE> has been defined, which when executed,
adds <CODE>10</CODE> to its parameter.  A variable <CODE>b</CODE> has also been
declared and initialized to zero before it is passed to
<CODE>add_10</CODE>.  What will be the value of <CODE>b</CODE> after the call to
<CODE>add_10</CODE>?  If <B>S-Lang</B> were a language that passed parameters by
reference, the value of <CODE>b</CODE> would be changed to
<CODE>10</CODE>.  However, <B>S-Lang</B> always passes by value, which means that
<CODE>b</CODE> would retain its value of zero after the function call.
<P><B>S-Lang</B> does provide a mechanism for simulating pass by reference
via the reference operator.  See the next section for more details.
<P>If a function is called with a parameter in the parameter list
omitted, the corresponding variable in the function will be set to
<CODE>NULL</CODE>.  To make this clear, consider the function
<BLOCKQUOTE><CODE>
<PRE>
     define add_two_numbers (a, b)
     {
        if (a == NULL) a = 0;
        if (b == NULL) b = 0;
        return a + b;
     }
</PRE>
</CODE></BLOCKQUOTE>

This function must be called with two parameters.  However, we can
omit one or both of the parameters by calling it in one of the
following ways:
<BLOCKQUOTE><CODE>
<PRE>
     variable s = add_two_numbers (2,3);
     variable s = add_two_numbers (2,);
     variable s = add_two_numbers (,3);
     variable s = add_two_numbers (,);
</PRE>
</CODE></BLOCKQUOTE>

The first example calls the function using both parameters;
however, at least one of the parameters was omitted in the other
examples.  The interpreter will implicitly convert the last three
examples to
<BLOCKQUOTE><CODE>
<PRE>
     variable s = add_two_numbers (2, NULL);
     variable s = add_two_numbers (NULL, 3);
     variable s = add_two_numbers (NULL, NULL);
</PRE>
</CODE></BLOCKQUOTE>

It is important to note that this mechanism is available only for
function calls that specify more than one parameter.  That is,
<BLOCKQUOTE><CODE>
<PRE>
     variable s = add_10 ();
</PRE>
</CODE></BLOCKQUOTE>

is <EM>not</EM> equivalent to <CODE>add_10(NULL)</CODE>.  The reason for this
is simple: the parser can only tell whether or not <CODE>NULL</CODE> should
be substituted by looking at the position of the comma character in
the parameter list, and only function calls that indicate more than
one parameter will use a comma.  A mechanism for handling single
parameter function calls is described in the next section.
<P>
<P>
<H2><A NAME="ss9.3">9.3 Referencing Variables</A>
</H2>

<P> 
<P>One can achieve the effect of passing by reference by using the
reference (<CODE>&amp;</CODE>) and dereference (<CODE>@</CODE>) operators. Consider
again the <CODE>add_10</CODE> function presented in the previous section.
This time we write it as
<BLOCKQUOTE><CODE>
<PRE>
     define add_10 (a)
     {  
        @a = @a + 10;
     }
     variable b = 0;
     add_10 (&amp;b);
</PRE>
</CODE></BLOCKQUOTE>

The expression <CODE>&amp;b</CODE> creates a <EM>reference</EM> to the variable
<CODE>b</CODE> and it is the reference that gets passed to <CODE>add_10</CODE>.
When the function <CODE>add_10</CODE> is called, the value of <CODE>a</CODE> will
be a reference to <CODE>b</CODE>.  It is only by <EM>dereferencing</EM> this
value that <CODE>b</CODE> can be accessed and changed.  So, the statement
<CODE>@a=@a+10;</CODE> should be read `add <CODE>10</CODE>' to the value of the
object that <CODE>a</CODE> references and assign the result to the object
that <CODE>a</CODE> references.
<P>The reader familiar with C will note the similarity between
<EM>references</EM> in <B>S-Lang</B> and <EM>pointers</EM> in C.  
<P>One of the main purposes for references is that this mechanism
allows reference to functions to be passed to other functions.  As
a simple example from elementary calculus, consider the following
function which returns an approximation to the derivative of another
function at a specified point:
<BLOCKQUOTE><CODE>
<PRE>
     define derivative (f, x)
     {
        variable h = 1e-6;
        return (@f(x+h) - @f(x)) / h;
     }
</PRE>
</CODE></BLOCKQUOTE>

It can be used to differentiate the function
<BLOCKQUOTE><CODE>
<PRE>
     define x_squared (x)
     {
        return x^2;
     }
</PRE>
</CODE></BLOCKQUOTE>

at the point <CODE>x = 3</CODE> via the expression
<CODE>derivative(&amp;x_squared,3)</CODE>.
<P>
<P>
<P>
<H2><A NAME="ss9.4">9.4 Functions with a Variable Number of Arguments</A>
</H2>

<P> 
<P><B>S-Lang</B> functions may be defined to take a variable number of
arguments.  The reason for this is that the calling routine pushes
the arguments onto the stack before making a function call, and it
is up to the called function to pop the values off the stack and
make assignments to the variables in the parameter list.  These
details are, for the most part, hidden from the programmer.
However, they are important when a variable number of arguments are
passed.
<P>Consider the <CODE>add_10</CODE> example presented earlier.  This time it
is written
<BLOCKQUOTE><CODE>
<PRE>
     define add_10 ()
     {
        variable x;
        x = ();
        return x + 10;
     }
     variable s = add_10 (12);  % ==&gt; s = 22;
</PRE>
</CODE></BLOCKQUOTE>

For the uninitiated, this example looks as if it
is destined for disaster.  The <CODE>add_10</CODE> function looks like it
accepts zero arguments, yet it was called with a single argument.
On top of that, the assignment to <CODE>x</CODE> looks strange.  The truth
is, the code presented in this example makes perfect sense, once you
realize what is happening.
<P>First, consider what happened when <CODE>add_10</CODE> is called with the
the parameter <CODE>12</CODE>.  Internally, <CODE>12</CODE> is
pushed onto the stack and then the function called.  Now,
consider the function itself.  <CODE>x</CODE> is a variable local to the
function.  The strange looking assignment `<CODE>x=()</CODE>' simply
takes whatever is on the stack and assigns it to <CODE>x</CODE>.  In
other words, after this statement, the value of <CODE>x</CODE> will be
<CODE>12</CODE>, since <CODE>12</CODE> will be at the top of the stack.
<P>A generic function of the form
<BLOCKQUOTE><CODE>
<PRE>
    define function_name (x, y, ..., z)
    {
       .
       .
    }
</PRE>
</CODE></BLOCKQUOTE>

is internally transformed by the interpreter to
<BLOCKQUOTE><CODE>
<PRE>
    define function_name ()
    {
       variable x, y, ..., z;
       z = ();
       .
       .
       y = ();
       x = ();
       .
       .
    }
</PRE>
</CODE></BLOCKQUOTE>

before further parsing.  (The <CODE>add_10</CODE> function, as defined above, is
already in this form.)  With this knowledge in hand, one can write a
function that accepts a variable number of arguments.  Consider the
function:
<BLOCKQUOTE><CODE>
<PRE>
    define average_n (n)
    {
       variable x, y;
       variable sum;
       
       if (n == 1) 
         {
            x = ();
            sum = x;
         }
       else if (n == 2)
         {
            y = ();
            x = ();
            sum = x + y;
         }
       else error ("average_n: only one or two values supported");
       
       return sum / n;
   }
   variable ave1 = average_n (3.0, 1);        % ==&gt; 3.0
   variable ave2 = average_n (3.0, 5.0, 2);   % ==&gt; 4.0
</PRE>
</CODE></BLOCKQUOTE>

Here, the last argument passed to <CODE>average_n</CODE> is an integer
reflecting the number of quantities to be averaged.  Although this
example works fine, its principal limitation is obvious: it only
supports one or two values.  Extending it to three or more values
by adding more <CODE>else if</CODE> constructs is rather straightforward but
hardly worth the effort.  There must be a better way, and there is:
<BLOCKQUOTE><CODE>
<PRE>
   define average_n (n)
   {
      variable sum, x;
      sum = 0;
      loop (n) 
        {
           x = ();    % get next value from stack
           sum += x;
        }
      return sum / n;
   }
</PRE>
</CODE></BLOCKQUOTE>

The principal limitation of this approach is that one must still
pass an integer that specifies how many values are to be averaged.
<P>Fortunately, a special variable exists that is local to every function
and contains the number of values that were passed to the function.
That variable has the name <CODE>_NARGS</CODE> and may be used as follows:
<BLOCKQUOTE><CODE>
<PRE>
   define average_n ()
   {
      variable x, sum = 0;
      
      if (_NARGS == 0) error ("Usage: ave = average_n (x, ...);");

      loop (_NARGS)
        {
           x = ();
           sum += x;
        }
      return sum / _NARGS;
   }
</PRE>
</CODE></BLOCKQUOTE>

Here, if no arguments are passed to the function, a simple message
that indicates how it is to be used is printed out.
<P>
<P>
<P>
<P>
<H2><A NAME="ss9.5">9.5 Returning Values</A>
</H2>

<P>
<P>As stated earlier, the usual way to return values from a function
is via the <CODE>return</CODE> statement.  This statement has the
simple syntax
<BLOCKQUOTE><CODE>
return <EM>expression-list</EM> ;
</CODE></BLOCKQUOTE>

where <EM>expression-list</EM> is a comma separated list of expressions.
If the function does not return any values, the expression list
will be empty.  As an example of a function that can return
multiple values, consider
<BLOCKQUOTE><CODE>
<PRE>
        define sum_and_diff (x, y)
        {
            variable sum, diff;

            sum = x + y;  diff = x - y;
            return sum, diff;
        }
</PRE>
</CODE></BLOCKQUOTE>

which is a function returning two values.
<P>It is extremely important to note that <EM>the calling routine must
explicitly handle all values returned by a function</EM>.  Although
some languages such as C do not have this restriction, <B>S-Lang</B> does
and it is a direct result of a <B>S-Lang</B> function's ability to return
many values and accept a variable number of parameters.  Examples
of properly handling the above function include
<BLOCKQUOTE><CODE>
<PRE>
       variable sum, diff;
       (sum, diff) = sum_and_diff (5, 4);  % ignore neither
       (sum, ) = sum_and_diff (5, 4);      % ignore diff
       (,) = sum_and_diff (5, 4);          % ignore both sum and diff
</PRE>
</CODE></BLOCKQUOTE>

See the section below on assignment statements for more information
about this important point.
<P>
<H2><A NAME="ss9.6">9.6 Multiple Assignment Statement</A>
</H2>

<P> 
<P><B>S-Lang</B> functions can return more than one value, e.g.,
<BLOCKQUOTE><CODE>
<PRE>
       define sum_and_diff (x, y)
       {
          return x + y, x - y;
       }
</PRE>
</CODE></BLOCKQUOTE>

returns two values.  It accomplishes this by placing both values on
the stack before returning.  If you understand how <B>S-Lang</B> functions
handle a variable number of parameters (section ???), then it
should be rather obvious that one assigns such values to variables.
One way is to use, e.g.,
<BLOCKQUOTE><CODE>
<PRE>
      sum_and_diff (9, 4);
      d = ();
      s = ();
</PRE>
</CODE></BLOCKQUOTE>
<P>However, the most convenient way to accomplish this is to use a
<EM>multiple assignment statement</EM> such as 
<BLOCKQUOTE><CODE>
<PRE>
       (s, d) = sum_and_diff (9, 4);
</PRE>
</CODE></BLOCKQUOTE>

The most general form of the multiple assignment statement is
<BLOCKQUOTE><CODE>
<PRE>
     ( var_1, var_2, ..., var_n ) = expression;
</PRE>
</CODE></BLOCKQUOTE>

In fact, internally the interpreter transforms this statement into
the form
<BLOCKQUOTE><CODE>
<PRE>
     expression; var_n = (); ... var_2 = (); var_1 = ();
</PRE>
</CODE></BLOCKQUOTE>

for further processing.
<P>If you do not care about one of return values, simply omit the
variable name from the list.  For example,
<BLOCKQUOTE><CODE>
<PRE>
        (s, ) = sum_and_diff (9, 4);
</PRE>
</CODE></BLOCKQUOTE>

assigns the sum of <CODE>9</CODE> and <CODE>4</CODE> to <CODE>s</CODE> and the
difference (<CODE>9-4</CODE>) will be removed from the stack.
<P>As another example, the <B>jed</B> editor provides a function called
<CODE>down</CODE> that takes an integer argument and returns an integer.
It is used to move the current editing position down the number of
lines specified by the argument passed to it.  It returns the number
of lines it successfully moved the editing position.  Often one does
not care about the return value from this function.  Although it is
always possible to handle the return value via
<BLOCKQUOTE><CODE>
<PRE>
       variable dummy = down (10);
</PRE>
</CODE></BLOCKQUOTE>

it is more convenient to use a multiple assignment expression and
omit the variable name, e.g.,
<BLOCKQUOTE><CODE>
<PRE>
       () = down (10);
</PRE>
</CODE></BLOCKQUOTE>
<P>Some functions return a <EM>variable number</EM> of values instead of a
<EM>fixed number</EM>.  Usually, the value at the top of the stack will
indicate the actual number of return values.  For such functions,
the multiple assignment statement cannot directly be used.  To see
how such functions can be dealt with, consider the following
function:
<BLOCKQUOTE><CODE>
<PRE>
     define read_line (fp)
     {
        variable line;
        if (-1 == fgets (&amp;line, fp))
          return -1;
        return (line, 0);
     }
</PRE>
</CODE></BLOCKQUOTE>

This function returns either one or two values, depending upon the
return value of <CODE>fgets</CODE>.  Such a function may be handled as in
the following example:
<BLOCKQUOTE><CODE>
<PRE>
      status = read_line (fp);
      if (status != -1)
        {
           s = ();
           .
           .
        }
</PRE>
</CODE></BLOCKQUOTE>

In this example, the <EM>last</EM> value returned by <CODE>read_line</CODE> is
assigned to <CODE>status</CODE> and then tested.  If it is non-zero, the
second return value is assigned to <CODE>s</CODE>.  In particular note the
empty set of parenthesis in the assignment to <CODE>s</CODE>.  This simply
indicates that whatever is on the top of the stack when the
statement is executed will be assigned to <CODE>s</CODE>.
<P>Before leaving this section it is important to reiterate the fact
that if a function returns a value, the caller must deal with that
return value.  Otherwise, the value will continue to live onto the
stack and may eventually lead to a stack overflow error.
Failing to handle the return value of a function is the
most common mistake that inexperienced <B>S-Lang</B> programmers make.
For example, the <CODE>fflush</CODE> function returns a value that many C
programmer's never check.  Instead of writing
<BLOCKQUOTE><CODE>
<PRE>
      fflush (fp);
</PRE>
</CODE></BLOCKQUOTE>

as one could in C, a <B>S-Lang</B> programmer should write
<BLOCKQUOTE><CODE>
<PRE>
      () = fflush (fp);
</PRE>
</CODE></BLOCKQUOTE>

in <B>S-Lang</B>.  (Many good C programmer's write <CODE>(void)fflush(fp)</CODE>
to indicate that the return value is being ignored).
<P>
<P>
<H2><A NAME="ss9.7">9.7 Exit-Blocks</A>
</H2>

<P>
<P>An <EM>exit-block</EM> is a set of statements that get executed when a
functions returns.  They are very useful for cleaning up when a
function returns via an explicit call to <CODE>return</CODE> from deep
within a function.
<P>An exit-block is created by using the <CODE>EXIT_BLOCK</CODE> keyword
according to the syntax 
<BLOCKQUOTE><CODE>
EXIT_BLOCK { <EM>statement-list</EM> }
</CODE></BLOCKQUOTE>

where <EM>statement-list</EM> represents the list of statements that
comprise the exit-block.  The following example illustrates the use
of an exit-block:
<BLOCKQUOTE><CODE>
<PRE>
      define simple_demo ()
      {
         variable n = 0;

         EXIT_BLOCK { message ("Exit block called."); }

         forever
          {
            if (n == 10) return;
            n++;
          }
      }
</PRE>
</CODE></BLOCKQUOTE>

Here, the function contains an exit-block and a <CODE>forever</CODE> loop.
The loop will terminate via the <CODE>return</CODE> statement when <CODE>n</CODE>
is 10.  Before it returns, the exit-block will get executed.
<P>A function can contain multiple exit-blocks, but only the last
one encountered during execution will actually get executed.  For
example,
<BLOCKQUOTE><CODE>
<PRE>
      define simple_demo (n)
      {
         EXIT_BLOCK { return 1; }
         
         if (n != 1)
           {
              EXIT_BLOCK { return 2; }
           }
         return;
      }
</PRE>
</CODE></BLOCKQUOTE>

If <CODE>1</CODE> is passed to this function, the first exit-block will
get executed because the second one would not have been encountered
during the execution.  However, if some other value is passed, the
second exit-block would get executed.  This example also
illustrates that it is possible to explicitly return from an
exit-block, although nested exit-blocks are illegal.
<P>
<P>
<HR>
<A HREF="slang-10.html">Next</A>
<A HREF="slang-8.html">Previous</A>
<A HREF="slang.html#toc9">Contents</A>
</BODY>
</HTML>