/*
    Difference between call-by-value and call-by-reference functions. Nyhoff P357-365.
    
    Functions can only return one value, so what if we want them to return multiple
    values. And what about efficiency?

    call-by-value semantics:
 
    <return type> function_name ( <input type> name )   
      {
         name is a local copy of the value of the variable the function was called with.
         changing name, does not affect the original variable, since its a local copy.
      }

   call-by-reference semantics:   
    
    <return type> function_name ( <input type> & name )    NOTE &
      {
         name IS now the variable the function was called with. Just with a local name.
         changing name, changes the value of the variable the function was called with.      
      }
      
   call-by-const-reference semantics:   
    
    <return type> function_name ( const <input type> & name )    NOTE const and &
      {
         name IS now the variable the function was called with. Just with a local name.
         Since we have specified name as a constant, the compiler will not compile code
         that tries to change it.
      }

   Call by reference is faster, since no copying is involved. Especially when using
   variable of complex classes, where the copying overhead would kill performance.   

   Call by const-reference is fast and safe, since the original variable is protected. 

   1) Try removing the remarks and see the error message the compiler generates.
   2) Write a function that returns the roots of a 2nd degree equation.
    
        void roots(double a,double b, double c, int& nroot, double& root1, double& root2 );
        
        Variables ax^2 + bx + c = 0 
        nroot 0,1,2   depending on the number of roots.
        root1, root2  the value of the root(s)
   
*/

#include <iostream>
using namespace std;

double multiply_by_two_1(double z)        // z is a COPY of value of the calling variable (x)
{
  z*=2;
  return z;
}


double multiply_by_two_2(double &z)       // z IS the calling variable (x), just with a different name.
{
  z*=2;
  return z;
}

double multiply_by_two_3(const double &z) // z IS the calling variable (x), just with a different name.
{
//  z*=1;                                 // fails const references must not be modified.
  return z*2;
}

int main()
{
   double x=42.0;
   
   cout << "x=" << x << endl;                 // 42
   cout << multiply_by_two_1(x) << endl;      // 84 since 42*2 
   cout << "x=" << x << endl;                 // still 42
   cout << multiply_by_two_2(x) << endl;      // 82 since 42*2 
   cout << "x=" << x << endl;                 // but value of x was changed inside multiply_by_two_2!
   cout << multiply_by_two_3(x) << endl;      // 168 since 84*2 
   cout << "x=" << x << endl;                 // x is still 84

/*
   cout << multiply_by_two_1(21) << endl;     // 42 since 21*2 
   cout << multiply_by_two_2(21) << endl;     // Can not be compiled, a the constant 21 can not be modified! 
*/

   return 0;
}
