Please send questions to st10@humboldt.edu .

Adding mutation to our classes...

*   overloading - you can have multiple methods
    with the same name in a class, as long as the
    the headers for those methods are sufficiently
    different (different number of parameters,
    significantly-different-enough types of 
    parameters if one has methods with the same
    number of parameters)

    *   ..you don't have to think of even more
        good names for similar actions...
	...or remember as many method names...
	...or recognize them

SO -- a method that changes a data field of
      a class instance is sometimes/often
      called a modifier (or setter, or mutator, etc.)
      method;

*   when designing a class, you need to provide
    a modifier method for each data field that
    a user can reasonably be allowed to change;

CLASS STYLE STANDARD:
*   for "plain vanilla" modifier functions,
    that simply allow a user to set a class data
    field to a value of their choice,

    you are expected to name these using the
    pattern:
    set_<data_field_name> (or set<Data_field_name>)

So, for boa, let's say we want the user to be
    able to change all 3 data fields of a boa
    instance.
The modifier methods should (based on the above)
be:
    set_length  (also OK: setLength)
    set_color   (also OK: setColor)
    set_food    (also OK: setFood)

*   since a modifier method is intended to let the user change
    a data field's value -- how does the user indicate that?
    ...with a parameter intended to contain the desired new
    value; (give it a *descriptive* name DIFFERENT from
    the data field name...)

*   since the point with a modifier method is simply to 
    change the data field, this method doesn't need to
    produce anything --
    *   but a C++ function or method needs to have a return
        type;

    *   fortunately, C++ has a keyword indicating nothing is
        to be returned -- void!

    *   SO, when a function or method's purpose is just to have
        a side-effect -- and not produce/return anything -- it
	should have a return type of void

*   SO -- here are some good method headers for boa's
    modifier methods -- add these to the public part of
    boa's class definition in boa.h:

    void set_length(double new_length);
    void set_color(string new_color);
    void set_food(string new_food);

*   and add their implementations to boa.cpp --
    *   remember to add boa:: in front of the method names in their
        headers in boa.cpp!

    *   DON'T put a semicolon after the header when implementing
        the method in boa.cpp!

    *   and really, all these need to do is to *assign* the desired
        new value to the appropriate data field -- for example,

void boa::set_length(double new_length)
{
    length = new_length;
}

*   and now -- these need to be tested!
    *   need to add tests for the modifier methods to boa_test.cpp;

    *   basically: call each modifier method to change something
        in an instance of the class, and then check that all of the
	data fields have indeed been changed;

    *   now it becomes easier if we make some bool variables to hold
        different sets of tests -- here the selector tests and the 
        modifier tests -- and then return the result of and'ing those
	test results;

    *   that is, add these bool variables to boa_test, after george's
        declaration:

        // these are to keep track of my test results
     
        bool selector_results;
        bool modif_results;

    *   then change the current return statement to instead set
        selector_results:

        selector_results =
           (george.get_color() == "fuschia") and
           (george.get_length() == 50) and
           (george.get_food() == "crocodiles");

    *   now call each modifier on george (on your instance), changing
        each of that instance's data fields -- for example,

            // exercise the modifier methods
    
            george.set_color("purple");
            george.set_length(75);
            george.set_food("dragons");

    *   ...and set modif_results to the result of comparing all
        the data field values to what they should be now:

        modif_results = 
           (george.get_color() == "purple") and
           (george.get_length() == 75) and
           (george.get_food() == "dragons");

    *   and NOW return the result of and'ing selector_results and
        modif_results:

	return (selector_results and modif_results);

*   compile, and see if you get true when you run boa_test...!

ZERO-ARGUMENT CONSTRUCTOR:

*   ...it is considered GOOD PRACTICE to always
    provide a zero-argument constructor for a class;

    (there are times when C++ automatically creates
    a class instance "for" you, and a 0-argument 
    constructor makes this less awkward...)

*   if we add a 0-argument boa constructor,
    we're overloading the boa constructor --
    we're providing 2 with the same name

*   SO -- what do we add to boa.h?
    ...in the public: part of the boa class definition,
       preferably right around where you defined the 3-argument boa
       constructor, add the definition for the 0-argument one:

       boa( );

*   And, what do we add to boa.cpp?
    ...its implementation -- and since the user isn't specifying
       values for the data fields, we need to assign DEFAULT values
       to each;

    ...(don't forget the boa:: before the constructor name!)

    ...often, you might set a string data field to "" (the empty string)
       or a numeric data field to 0 -- here, we're being a little more
       whimsical. You should decide on reasonable default data field values
       based on the setting your program is being used in.

    ...we ended up with:

boa::boa( )
{
    color = "green";
    length = 6;
    food = "alligators";
}

*   but, again -- gotta TEST this!
    And this brings up an IMPORTANT C++ SYNTAX QUIRK --
    when you make a declaration of a variable using a 0-argument
        constructor, you need to OMIT the usual empty parentheses!

    *   so, to declare a boa named carol using the 0-argument
        constructor, you use:

	boa carol;

	(not the typical 0-argument function call style of boa carol( );)

        (can you see that     boa carol( );  // DOES NOT WORK
         also looks like a function header for a function carol that
         expects nothing and produces a boa? That ambiguity makes it
	 unacceptable...thus this syntax quirk!)

*   So -- we'll declare carol as shown above to boa_test.cpp,
    and then add tests making sure that its data fields are what
    the 0-argument should set them to to the expression setting
    selector_results:

    selector_results =
           (george.get_color() == "fuschia") and
           (george.get_length() == 50) and
           (george.get_food() == "crocodiles") and
           (carol.get_color() == "green") and
           (carol.get_length() == 6) and
           (carol.get_food() == "alligators");

...and compile boa_test, and make sure it produces true...

*   next, adding some OTHER methods to boa...