CS 4: Lecture 5
                         Wednesday, February 1, 2006

Why Write Methods?
------------------
(1)  Suppose you have a complicated operation you want to do in many different
     places in your code, like computing the length of a vector.  You can write
     one method to compute the length of a vector, and use it over and over
     again.  This keeps your code much cleaner and easier to read than if you
     cut-and-paste the code over and over again.

       lengthp = position.length();
       lengthv = velocity.length();
       lengtha = acceleration.length();

(2)  Suppose you need to change the way you compute the length of a vector--
     for example, you were doing it wrong and need to correct your code.  You
     only need to change your code in one place, instead of a hundred places.

(3)  Very long programs are hard to read.  You can make them much easier by
     dividing your code into big operations, each comprising many lines of
     code, and moving them into separate methods with meaningful names.

       public void static main() {
         Data data = getData();                   // Was 500 lines of code.
         double energy = data.computeEnergy();    // Was 700 lines of code.
         data.outputResult(energy);               // Was 600 lines of code.
       }

     Then you can break "getData" and "computeEnergy" and "outputResult" into
     smaller methods, and those into smaller methods, and so on.  This is how
     really large programs get written:  by breaking them down into coherent
     pieces that can each be understood independently.

(4)  By associating methods (code) with the objects they manipulate, you
     organize your code in a logical, more readable manner.  You'll understand
     this better when you've had more programming experience.

Pass by Value
-------------
When you call a method and pass parameters to it, the parameters are passed
_by_value_.  This means that the method has a _copy_ of the actual parameter,
and cannot change the original.

Let's look at an example.

  public static void main(String[] args) {
    long c = 1;
    doNothing(c);
    System.out.println(c);
  }

  static void doNothing(long x) {
    x = 2;
  }

When you run this program, Java begins execution with the main method, which
declares a variable "c" and sets it to one:

      -----
    c | 1 |
      -----

When "main" calls "doNothing(c)", the doNothing method declares a _new_
variable "x" to hold the value of the parameter, and _copies_ the value of c
into x.  That's what in means to pass parameters by value.

      -----         -----
    c | 1 |       x | 1 |
      -----         -----

Next, the doNothing method assigns x a value of 2.

      -----         -----
    c | 1 |       x | 2 |
      -----         -----

The important thing to notice is that the value of c is unchanged.  In fact,
there is _no_ way the doNothing method can change the value of c.

Next, the doNothing method ends.  When a method ends, all the parameters and
local variables declared inside that method disappear forever.

      -----
    c | 1 |
      -----

To make it a little more confusing...we could have called doNothing's parameter
"c".

  static void doNothing(long c) {
    c = 2;
  }

But things would have turned out exactly the same way.  Confusingly, we would
have two different variables named c.

      -----         -----
    c | 1 |       c | 2 |
      -----         -----

But the left "c" can only be accessed from inside "main", and the right "c" can
only be accessed from inside "doNothing".  "Pass by value" still works the same
way:  main's c gets copied into doNothing's c, and then none of the changes
doNothing makes to its c have any effect on main's c.

Constructors
------------
A constructor is a method that constructs an object.  Let's write a constructor
that constructs a Quantity.  The constructor won't actually contain code that
does the creating; rather, Java provides a brand new object for us right at the
beginning of the constructor, and all you have to write in the constructor is
code to initialize the new object (or not even that).

class Quantity {
  // Include all the stuff from Lecture 4 here.

  public Quantity(String myUnit) {
    amount = 1.0;
    unit = myUnit;
  }
}

Notice that the constructor is named "Quantity", and it returns an object of
class "Quantity".  This constructor is called when we write "new Quantity(s)",
where s is a String object.  Now, we can shorten initializing a frequency.

  Quantity frequency = new Quantity("Hertz");
  frequency.contents();

The output is:

  I represent 1.0 Hertz.

In Lecture 4, we constructed a Quantity object without writing a constructor
first.  How did we do that?  Java provides every class with a default
constructor, which takes no parameters and does no initializing.  Hence, when
we wrote

  new Quantity()

we created a new, blank Quantity.  If the default constructor were defined
explicitly, it would look like this:

  public Quantity() {
  }

You can override the default constructor by explicitly writing your own
constructor with no parameters.

  public Quantity() {
    amount = 0.0;
    unit = "thingies";
  }

Warning:  if you write your own Quantity constructor, even if it takes
parameters, the default constructor goes away.  If you want to have the default
Quantity constructor (with no parameters) _and_ another Quantity constructor
(with parameters), you must define both explicitly.