references

intro
                  PASSING VARIABLES BY REFERENCE
                  ==============================


   *************** example function 1 **********************

         void fun (int a, int b)
         {
           mixed c;
         } 

   ********************************************************

   a,b: [argument variables-Mateese creation] formal parameter
   c  : local variable

   Mateese says: The only difference between them is in the way they get 
   their initial values.

   Mateese says: When the function is called, the driver creates enough 
   space for these three variables, initialises them somehow, and lets 
   the function loose on it.

   Mateese says: The space for this variables exists only for this function 
   - so nothing the function does to the variables is visible outside.

   Mateese says: Consider the call: fun(2, 3).

   Mateese says: When calling the function, the driver creates the space 
   for the variables and initializes them.

   Mateese says: Variable c is local, it is initialised to 0. Variables a and b
   are argument variables, so their values are taken from the given arguments,
   namely 2 and 3.

   Mateese says: A more complicated call now. We have in the caller a 
   variable 'd':


   **************** example function 2 *******************************

       fun2()  {
         d = 3;
         fun(d,4);
       }

       fun(int a, int b)
       { 
         mixed c;
       }

   *******************************************************************


   Mateese says: What happens here is that the driver first replaces the 
   variable 'd' in the arguments by its value (it is said to copy the value), 
   yielding fun(3,4) as call.

   Mateese says: The rest is as usual: the space for fun's variables is
   allocated, a and b are initialized from the arguments to 3 and 4.

   Mateese says: Now the tricky part of references...
   Mateese smiles demonically.

   ************************* example function 3 *********************

       fun2()  {
         d = 3;
         fun(&d, 4);
       }
       fun(int a, int b)
       { 
         mixed c;
       }

   *******************************************************************

   Mateese says: This time, the driver recognizes the & symbol and does _not_
   replace the variable by its value.

   Mateese says: Instead, when allocating the space for fun's variables, 
   it just creates enough space for the variables b and c.

   Mateese says: For the argument variable a, the space of the caller's d is
   reused, and with it the value which happens to be in it.

   Mateese says: So, if fun() assigns any value to 'b', this takes place in its
   own space.

   Mateese says: But if fun() assigns anything to 'a', the space owned by the
   caller to hold its variable 'd' is used - any change to a within fun() will
   therefore also affect variable 'd'.

   say so it goes upwards? I change a in fun(), and whatever called it 
   also gets changed?

   Mateese says: Correct.

   Mateese says: Take a look at this:


   ********************* example function 4 ***************************

         

            void fun (int a, int b)
            {
              mixed c;
              a = 2;
              b = 1;
              c = -1;
            }

            void caller ()
            {
              int d, e;

              d = 8;
              e = 5;
              fun(d, &e);
            }

   *********************************************************************


   Mateese says: What values do d and e contain, and why?

   say the caller calls fun, puts 8 into d?  but then d becomes a, 
   which is set to 2
     
   say but d in caller doesn't change
 
   Mateese says: Right.
   Mateese says: Why?

   say a becomes 2, but since it's not passed by reference, it only 
   changes in the second fun, not the calling fun

   say which on the other hand, e is called by reference.

   Mateese nods.
 
   say it is initially 5 in caller(), gets sent to fun(),
   put into b. Then b gets changed in fun()
 
   say so both b and e are now 1
  
   Mateese says: Right.

   Mateese says: Another way to put it (you will read it eventually somewhere)
   also contains hints about what happens.

   Mateese says: d is passed 'by value': the driver creates fresh space for the
   variable a and copies the _value_ from d into a.

   Mateese says: e is passed 'by reference': the driver does not create fresh
   space for b, but instead lets b _refer_ to the space of e.

   Mateese would like to explain what happens if you pass to many or not 
   enough arguments.

   Mateese says: It's really simple, compared to references.
 
   Mateese says: Consider a slightly different function to call:

   ******************** example function 5 ******************************


          void fun (mixed pl, int level, int qp, int age)
          {
            if (stringp(pl))
              pl = find_object(pl);
            level = pl->QueryLevel();
            qp = pl->QueryQP();
            age = pl->QueryAge();
          }
 
   *********************************************************************


   Mateese says: Ignore the function body for now.

   Mateese says: The proper way to call this function is: 
     fun(name, &lvl, &qp, &age).

   Mateese says: (Believe me that for now).

   Mateese says: If you call it this way: fun(name), the driver expands this
   internally to: fun(name, 0, 0, 0) and then performs the call.

   say why?

   Mateese says: Because the function has four argument variables, which can't
   suddenly cease to exist just because of some stupid caller.

   Mateese says: So the driver compromises and allocates the space for these
   variables and initialises them to 0.

   say ah...but if they are 0's, are they still variables?

   Mateese says: Right.

   say can I still use them?

   Mateese says: Within fun? Yes.

   Mateese says: The not-given arguments are treated as if passed by value, 
   the value being 0.

   Mateese says: The whole by-value/by-reference business is under control 
   of the caller - it's his fault if he gives you his variables by reference, 
   free for mutilation.

      ---------------------------------------------------
      fun(name)               === fun(name,   0,  0,   0)
      fun(name, lvl)          === fun(name, lvl,  0,   0)
      fun(name, lvl, qp)      === fun(name, lvl, qp,   0)
      fun(name, lvl, qp, age) === fun(name, lvl, qp, age)

      but note:

      fun(name, qp)           === fun(name, qp,   0,   0)
      ---------------------------------------------------

   Mateese says: Too many arguments are even easier: all extra arguments are
   ignored

      ----------------------------------------------------------------------
      fun(name, lvl, qp, age, foo, bar, baz, etc) === fun(name, lvl, qp, age)
      -----------------------------------------------------------------------

   Mateese says: So, I did chose this latter function with purpose: 
   it takes the name of a player or the player object itself as argument, 
   and puts some information from it into the other argument variables.

   Mateese says: In your case, you have the player name available, and are
   interested in the number of qp he has.

   Mateese says: Lets say, the name is in the caller variable 'who', and 
   you want the QP amount be placed into the variable 'qp'.

   Mateese says: The proper call to fun is now:  fun(who, 0, &qp)

   Mateese says: The first argument, who, is clear: the function needs 
   the player name to operate on.

   Mateese says: We don't want our variable to be changed accidentally, so we
   pass it by value.

   Mateese says: But we want the function to return the QP amount into qp, 
   so we pass the qp variable by reference.

   Mateese says: Between the name and the qp, the function expects the
   lvl-variable, which we aren't interested in, so we just provide a dummy,
   the value 0. The age variable comes last and can safely be omitted.
 
   say ok...Q: if the fun gets called in /std/guild, how could the player 
   name get changed?

   Mateese says: Look at the start of the function:


         void fun (mixed pl, int level, int qp, int age)
         {
           if (stringp(pl))
           pl = find_object(pl);


   say and that could change the poor player's name?

   Mateese says: If we call the function and pass a _name_ 'by reference', the
   function would change the callers variable.

   Mateese says: No, the player's name wouldn't be changed, but the caller will
   run into trouble.
 
   Mateese says: Example:

   ********************** example function 6 ****************************

       void caller()
       {
         string who;
         int    qp;

         who = "any name";
         fun(&who, 0, &qp);  // fun() changes who from a string into an object!
         write("Player "+who+" has "+qp+" QP.\n"); 
         // runtime error: who is not a strg
       }

   *********************************************************************

   Mateese says: So, unless you really _want_ your variables be changed, pass
   them by value only :-)