                     Chapter 5 - Modula-2 Procedures


             In  order to define the procedure, we will need to  lay
        some groundwork in the form of a few definitions.

        Program  Heading  - This  is the easiest part  since  it  is
             only  one  line,  at least it has been in  all  of  our
             programs  up  to this point.   It is simply the  MODULE
             line,  and it never needs to be any more involved  than
             it  has  been up to this point,  except for  one  small
             addition which we will cover in a later chapter.

        Declaration  Part - This is the part of the Modula-2  source
             code in which all constants,  variables, and other user
             defined auxiliary operations are defined.   In some  of
             the  programs we have examined,  there have been one or
             more  VAR declarations and in one case a  constant  was
             declared.    These  are  the  only  components  of  the
             declaration  part we have used up to this time.   There
             are  actually four components in the declaration  part,
             and  the procedures make up the fourth part.   We  will
             cover the others in the next chapter.

        Statement  Part  - This  is the last part  of  any  Modula-2
             program,  and it is what we have been calling the  main
             program.   It  always  exists bounded by  the  reserved
             words  BEGIN  and  END  just as it has in  all  of  our
             examples to this point.

             It   is  very  important  that  you  grasp  the   above
        definitions because we will be referring to them  constantly
        during  this chapter,  and throughout the remainder of  this
        tutorial.   With that introduction, let us look at our first
        Modula-2 program with a procedure in it.   It will, in fact,
        have three procedures.

                            WHAT IS A PROCEDURE?

             A Procedure is a group of statements, either predefined
        by  the  compiler writer,  or defined by you,  that  can  be
        called  upon to do a specific job.   In this chapter we will
        see  how  to  write  and  use  a  procedure.    During  your
        programming in the future, you will use many procedures.  In
        fact,  you have already used some because the "WriteString",
        "WriteLn", etc procedures you have been using are predefined
        procedures.

             Load and display the program named PROCED1.MOD for your
        first look at a user defined procedure.  In this program, we
        have the usual header with one variable defined.  Ignore the
        header and move down to the main program beginning with line
        26.  We will come back to all of the statements prior to the
        main program in a few minutes.


                                 Page 29









                     Chapter 5 - Modula-2 Procedures



             The  main  program is very easy to understand based  on
        all of your past experience with Modula-2.  First we somehow
        write  a header (WriteHeader),  then write a message  out  8
        times  (WriteMessage),  and finally we write an  ending  out
        (WriteEnding).   Notice  that  with the long names  for  the
        parts,   no  comments  are  needed,   the  program  is  self
        documenting.   The  only  problem we have is,  how does  the
        computer  actually  do the three steps we  have  asked  for.
        That  is  the purpose for the 3 procedures  defined  earlier
        starting  in lines 8,  14,  and 20.   Modula-2 requires that
        nothing  can  be  used until it has  been  defined,  so  the
        procedures  are  required to be defined prior  to  the  main
        program.   This  may  seem a bit backward to you if you  are
        experienced in some other languages like FORTRAN,  BASIC, or
        C, but it will make sense eventually.

                       HOW DO WE DEFINE A PROCEDURE?

             We will begin with the PROCEDURE at line 8.   First  we
        must use the reserved word PROCEDURE followed by the name we
        have  chosen for our procedure,  in this case  "WriteHeader"
        which  is required to follow all of the rules for naming  an
        identifier.   Following  the PROCEDURE line,  we can include
        more IMPORT lists, define variables, or any of several other
        things.   We will go into a complete definition of this part
        of  the  program  in the next chapter.   I  just  wanted  to
        mention  that other quantities could be inserted  here.   We
        finally come to the procedure body which contains the actual
        instructions  we wish to execute in the procedure.   In this
        case,  the procedure body is very simple,  containing only a
        "WriteString" and a "WriteLn" instruction, but it could have
        been as complex as we needed to make it.

             At  the  end of the procedure,  we once again  use  the
        reserved  word END followed by the same name as  we  defined
        for  the procedure name.   In the case of a  procedure,  the
        final  name is followed by a semicolon instead of a  period.
        Other  than  this small change,  a procedure  definition  is
        identical to that of the program itself.

             When  the  main  program  comes  to  the  "WriteHeader"
        statement, it knows that it is not part of its standard list
        of executable instructions, so it looks for the user defined
        procedure  by  that name.   When it finds it,  it  transfers
        control  of  the  program  sequence  to  there,  and  begins
        executing those instructions.   When it executes all of  the
        instructions in the procedure, it finds the END statement of
        the  procedure and returns to the next statement in the main
        program.   When the main program finally runs out of  things
        to do, it finds the END statement and terminates.


                                 Page 30









                     Chapter 5 - Modula-2 Procedures



             As the program executes the FOR loop, it is required to
        call the "WriteMessage" procedure 8 times, each time writing
        its  message  on  the monitor,  and  finally  it  finds  and
        executes  the "WriteEnding" procedure.   This should be very
        straightforward  and should pose no real problem for you  to
        understand.   When  you think you understand what it  should
        do, compile and run it to see if it does.

                  NOW FOR A PROCEDURE THAT USES SOME DATA

             The  last  program  was interesting to show you  how  a
        procedure works but if you would like to see how to get some
        data into the procedure,  load and display the program named
        PROCED2.MOD.   We will once again go straight to the program
        starting in line number 25.   We immediately notice that the
        program  is nothing more than one big FOR loop which  we  go
        through 3 times.  Each time through the loop we call several
        procedures,  some that are system defined, and some that are
        user  defined.   This  time instead of the simple  procedure
        name,  we  have  a variable in the  parentheses  behind  the
        variable name.   In these procedures, we will take some data
        with us to the procedures,  when we call them,  just like we
        have  been  doing  with  the  "WriteString"  and  "WriteInt"
        procedures.

            We   will  take  some  data  to  the   procedure   named
        "PrintDataOut"  where  it will be  printed.   The  procedure
        "PrintDataOut"  starting  in line 9 also contains a pair  of
        parentheses  with a variable named "Puppy" which is of  type
        INTEGER.   This  says that it is expecting a variable to  be
        passed  to  it from the calling program and it  expects  the
        variable to be of type INTEGER.  Back to the main program we
        see,  on line 28,  that the program did make the call to the
        procedure with a variable named "Thing" which is an  INTEGER
        type variable, so everything is fine.  The procedure prefers
        to  call  the  variable  passed to it "Puppy"  but  that  is
        perfectly  acceptable,   it  is  the  same  variable.    The
        procedure writes the value of "Puppy",  which is really  the
        variable  "Thing"  in the main program,  in a line  with  an
        identifying string, then changes the value of "Puppy" before
        returning to the main program.

             Upon  returning  to  the main  program,  we  print  out
        another line with three separate parts (notice the indenting
        and the way it makes the program more readable),  then calls
        the  next procedure "PrintAndModify" which appears to do the
        same thing as the last one.   Indeed, studying the procedure
        itself  leads you to believe they are the same,  except  for
        the  fact that this one prefers to use the name "Cat" for  a
        variable  name.   There  is  one subtle difference  in  this


                                 Page 31









                     Chapter 5 - Modula-2 Procedures


        procedure, the reserved word VAR in the header, line 17.

                     CALL BY VALUE & CALL BY REFERENCE

             In the first procedure, the word VAR was omitted.  This
        is  a  signal to the compiler that this procedure  will  not
        actually  receive the variable reference,  instead  it  will
        receive  a  local copy of the variable which it can  use  in
        whatever way it needs to.   When it is finished, however, it
        can  not  return  any changes in the variable  to  the  main
        program  because  it  can  only work with its  copy  of  the
        variable.  This is therefore a one-way variable, it can only
        pass  data  to the procedure.   This is sometimes  called  a
        "call  by value" or a "value parameter" in literature  about
        Modula-2.

             In  the second procedure,  the word VAR  was  included.
        This   signals  the  compiler  that  the  variable  in  this
        procedure  is meant to be actually passed to the  procedure,
        and not just the value of the variable.   The procedure  can
        use  this variable in any way it desires,  and since it  has
        access to the variable in the main program,  it can alter it
        if it so desires.   This is therefore a two-way variable, it
        can  pass  data from the main program to the  procedure  and
        back again.   This is sometimes called a "call by reference"
        or a "variable parameter" in literature about Modula-2.

                           WHICH SHOULD BE USED?

             It  is up to you to decide which of the  two  parameter
        passing  schemes you should use for each  application.   The
        "two-way" scheme seems to give the greatest flexibility,  so
        your first thought is to simply use it everywhere.  But that
        is  not  a good idea because it gives  every  procedure  the
        ability  to  corrupt  your  main  program   variables.    In
        addition,  if  you  use a "call by value" in  the  procedure
        definition,  you have the ability to call the procedure with
        a  constant  in that part of the call.   A good  example  is
        given  in  lines 12,  20,  30,  34,  and 38 of  the  present
        program.   If  "WriteInt"  were  defined  with  a  "call  by
        reference",  we  could not use a constant here,  but instead
        would  have  to set up a variable,  assign  it  the  desired
        value,  then use the variable name instead of the 5.   There
        are  other  considerations but they are beyond the level  of
        our study at this point.

                  BACK TO THE PROGRAM ON DISPLAY, PROCED2

             We  have already mentioned that both of the  procedures
        modify  their  respective local variables,  but due  to  the
        difference  in "call by value" in the first,  and  "call  by


                                 Page 32









                     Chapter 5 - Modula-2 Procedures


        reference"  in the second,  only the second can actually get
        the modified data back to the calling program.   This is why
        they are named the way they are.   One other thing should be
        mentioned.   Since  it  is not good practice to  modify  the
        variable  used  to  control the  FOR  loop,  (and  downright
        erroneous  in many cases) we make a copy of it and  call  it
        "Thing"  for use in the calls to the procedures.   Based  on
        all  we  have said above,  you should be able to figure  out
        what the program will do, then compile and run it.

                     SEVERAL PARAMETERS PASSED AT ONCE

             Load  and display the program named PROCED3.MOD for  an
        example  of  a  procedure  definition  with  more  than  one
        variable being passed to it.   In this case four  parameters
        are  passed to this procedure.  Three of the parameters  are
        one-way  and  one is a two-way parameter.   In this case  we
        simply  add  the  three numbers and return it  to  the  main
        program.    Good  programming  practice  would  dictate  the
        placement  of the single "call by reference" by  itself  and
        the  others  grouped together,  but it is more important  to
        demonstrate to you that they can be in any order you desire.
        This  is a very straightforward example that should pose  no
        problem to you. Compile and run it.

                             SCOPE OF VARIABLES

             Load and display the program PROCED4.MOD for a  program
        which  can  be  used to define scope of variables  or  where
        variables  can be used in a program.   The  three  variables
        defined in lines 6, 7, and 8, are of course available in the
        main program because they are defined prior to it.   The two
        variables  defined in the procedure are available within the
        procedure because that is where they are defined.   However,
        because the variable "Count" is defined both places,  it  is
        two  completely  separate variables.   The main program  can
        never use the variable "Count" defined in the procedure, and
        the procedure can never use the variable "Count" defined  in
        the  main  program.   They are two completely  separate  and
        unique variables with no ties between them.   This is useful
        because  when your programs grow,  you can define a variable
        in  a procedure,  use it in whatever way you wish,  and  not
        have  to worry that you are corrupting some  other  "global"
        variable.   The  variables  in the main program  are  called
        "global variables" because they are available everywhere.

             In  addition  to the above scope  rules,  the  variable
        named "Apple" in the procedure, is not available to the main
        program.   Since  it is defined in the procedure it can only
        be used in the procedure.   The procedure effectively builds
        a  wall around the variable "Apple" and its own  "Count"  so


                                 Page 33









                     Chapter 5 - Modula-2 Procedures


        that neither is available outside of the procedure.  We will
        see  in  the  next chapter that procedures can  be  "nested"
        leading  to further hiding of variables.   This  program  is
        intended to illustrate the scope of variables,  and it would
        be good for you to study it, then compile and run it.

                   A PROCEDURE CAN CALL ANOTHER PROCEDURE

             Load  and display the program named PROCED5.MOD for  an
        example of procedures that call other procedures.   Study of
        this  program will reveal that procedure "Three" starting on
        line 19 calls procedure "Two" which in turn calls  procedure
        "One".  The main program calls all three, one at a time, and
        the  result is a succession of calls which should be  rather
        easy for you to follow.   The general rule is,  "any program
        or  procedure  can  call any other procedure that  has  been
        previously  defined,  and is visible to it."  (We  will  say
        more  about  visibility  later.)  Study  this  program  then
        compile and run it.

                            A FUNCTION PROCEDURE

             Load  and display the program named FUNCTION.MOD for an
        example  of  a  "Function  Procedure".    This  contains   a
        procedure  very much like the ones we have seen so far  with
        one difference.   In the procedure heading, line 6, there is
        an added ":  INTEGER" at the end of the argument list.  This
        is a signal to the system that this procedure is a "function
        procedure"  and it therefore returns a value to the  calling
        program  in a way other than that provided for by  parameter
        references  as we have used before.   In fact,  this program
        returns a single data value that will be of type INTEGER.

             In line 16 of the calling program,  we find the call to
        the  procedure  which  looks like the others  we  have  used
        except that it is used in an assignment statement as  though
        it is an INTEGER type variable.   This is exactly what it is
        and  when the call is completed,  the "QuadOfSum(Dogs,Cats)"
        will  be  replaced by the answer and then  assigned  to  the
        variable  "Feet".   The  entire call can therefore  be  used
        anyplace  in  a program where it is legal to use an  INTEGER
        type variable.   This is therefore a single value return and
        can  be very useful in the right situation.   In one of  the
        earlier  program,  we  used  the "sin"  and  "cos"  function
        procedures and this is exactly what they were.

             One additional point must be made here.   If a function
        procedure  does not require any parameters,  the call to  it
        must  include empty parentheses,  and the definition of  the
        procedure  must include empty parentheses also.   This is by
        definition of the Modula-2 language.


                                 Page 34









                     Chapter 5 - Modula-2 Procedures



             In  the  procedure,  we had to do  one  thing  slightly
        different  in order to get the return value and that was  to
        use  the RETURN reserved word.   Whenever we have  completed
        the  desired calculations or whatever we need to do,  we put
        the result that is to be returned to the main program in the
        parentheses  following  the RETURN and  the  procedure  will
        terminate, return to the calling program, and take the value
        with it as the answer.   Due to decision making, we may have
        several RETURN statements in the procedure but only one will
        be exercised with each call.   It is an error to come to the
        END  statement  of  a function procedure  since  that  would
        constitute  a  return  without  the benefit  of  the  RETURN
        statement,  and  no value would be returned to  the  calling
        program.

                             WHAT IS RECURSION?

             Recursion is simply a procedure calling itself.  If you
        have  never  been  introduced  to  recursion  before,   that
        definition sounds too simple but that is exactly what it is.
        You  have  probably seen a picture containing a  picture  of
        itself.   The picture in the picture also contains a picture
        of  itself,  the end result being an infinity  of  pictures.
        Load the file named RECURSON.MOD for an example of a program
        with recursion.

             In  the  main  program,  "Count" is set to  7  and  the
        procedure is called taking along "Count" as a parameter.  In
        the procedure, we display a line containing the value of the
        variable,  now  called  "Index",  and decrement it.  If  the
        variable  is greater than zero,  we call the same  procedure
        again,  this time entering it with the value of 6.  It would
        be  reasonably  correct to think of the system  as  creating
        another copy of the procedure for this call.   The  variable
        "Index"  would  be  reduced to 5,  and another copy  of  the
        procedure would be called.   Finally,  the variable would be
        reduced  to  zero  and the return  path  from  procedure  to
        procedure  would  be taken until the main program  would  be
        reached, where the program would terminate.

             Rather than making a complete new copy of the procedure
        for  each recursive call,  the same code would be  run  each
        time through and all of the data would be stored away on the
        "stack" each time through.   You have no need to worry about
        this  because it is all taken care of for you by the system.
        You  simply  call the same procedure as though it  were  any
        other  procedure and the system will worry about all of  the
        details except for one.   It is up to you to see that  there
        is  some mechanism by which the process will terminate.   If
        there were no decrementing statement in the procedure,  this


                                 Page 35









                     Chapter 5 - Modula-2 Procedures


        program  would  never  reach  an end  and  the  stack  would
        overflow,  resulting in an error message and termination  of
        the  program.   It  would be worth your time to  remove  the
        decrementing  statement and observe this,  after you compile
        and run it the way it is now.

             Recursion  can be very useful for those  problems  that
        warrant  its  use.   This  example is a very stupid  use  of
        recursion,  but is an excellent method for giving an example
        of  a  program  with recursion that is simple  and  easy  to
        understand.

                       DIRECT AND INDIRECT RECURSION

             This   example  uses  direct  recursion   because   the
        procedure calls itself directly.  It is also possible to use
        indirect recursion where procedure "A" calls "B",  "B" calls
        "A",  etc.   Either method is available and useful depending
        on the particular circumstances.


        PROGRAMMING EXERCISES

        1.   Write a program to write your name, address, and phone
             number on the monitor with each line in a different
             procedure.

        2.   Add a statement to the procedure in RECURSON to display
             the  value  of "Index" after the call to itself so  you
             can see the value increasing as the recurring calls are
             returned to the next higher level.

        3.   Rewrite TEMPCONV from chapter 4 putting the centigrade
             to farenheit formula in a function procedure.



















                                 Page 36

