The set-multiset assignment.


R. Clayton (rclayton@monmouth.edu)
Fri, 11 Aug 2000 15:14:30 -0400 (EDT)


The set-multiset programming assignments have been graded and are available.
Here are a few comments on the assignment and on programming in general:

 1 The assignment was a set-multiset programming assignment, with the
   expectation that you'd actually use a set or multiset or two in your
   assignment. Those of you that managed to avoid using both sets and
   multisets aren't going to get as good a grade as those that managed to
   shoehorn a set or multiset or two into their assignments.

   You should know that I have a similar expectation for the map-multimap
   assignment.

 2 Those of you that did use a set or multiset or two didn't quite put them to
   appropriate use. The general approached used was

     order_msgs(word) {

       multiset<msg, msg_greater> msgs

       for each message m in msg_list do
         m.count = the number of times word appears in m.header
         msgs.insert(m)

       msg_list.erase()
       for each m in msgs do
         msg_list.push_back(m)
       }

     msg_greater(m1, m2) {
       return m1.order > m2.order
       }

   The problem with this approach is that it doesn't use multisets in any
   essential way. The above code is equivalent to (not quite, see below)

     order_msgs(word) {
       for each message m in msg_list do
         m.count = the number of times word appears in m.header
       msg_list.sort(msg_greater)
       }

   A more appropriate use of a multiset would have been to associate one with
   each message and store in it the words in the header of the associated
   message. This way the code "the number of times word appears in m.header",
   which most of you implemented from scratch, can be replace by a a call to
   count(word) on the proper multiset; see my example (when I get around to
   posting it) for details.

   There is a more serious problem with the first version of order_msgs(): it
   doesn't implement a stable sort. There is no guarantee (that I can find)
   that identical keys inserted into a set or multiset are ordered in the
   multiset using the order with which they were inserted. In other words, the
   only guarantee is that identical values will be grouped together; there is
   no guarantee that identical values will be grouped together by insertion
   order. It is by the luck of the implementation that the result of reading
   out the sequence of values from a multiset is a stable-sort sequence.

 3 It is a truth generally acknowledged that global variables are bad, and
   their use should be minimized. Global variables are bad because
   understanding how a global variable is used in a program requires
   understanding the entire program; a global variable can affect and be
   affected by any code anywhere in the program. Even if a program references
   a global variable in only one or two places, the entire program must be
   understood to ensure that those one or two places are the only references to
   the global variable.

   Using object-oriented programming techniques (or at least using objects in
   your programs) does not absolve you of the responsibility of avoiding global
   variables. In fact, you must become more diligent in avoiding global
   variables because object-oriented approaches tend to both increase the
   number of global variables used (via instance variables, which are
   essentially global variables relative to the class in which they're
   declared) and making it harder to understand the scope of any particular
   global variable (via inheritance, which can take an instance variable global
   in one class and make it global to an arbitrarily long chain of descendent
   classes).

   Even though global variables are a central feature of the object-oriented
   approach, you avoid using them in the same way you'd avoid using global
   variables in procedural programming: pass them around as subroutine
   parameters. Passing a global variable into a subroutine as a parameter
   turns the global variable into a local variable within the subroutine.

   For example, consider the following class

     class Message {

       private:
         int mcnt;

         void f(void) {
           // blah blah blah

           mcnt++;

           // blah blah blah
           }

         void g(void) {
           // blah blah blah

           f();

           // blah blah blah
           }
       }
       
   The private member function g() calls the private member function f(), which
   adds one to the instance variable (a.k.a. global variable) mcnt. The global
   reference go mcnt in f() can be eliminated by passing mcnt in as a parameter
   to f():

     class Message {

       private:
         int mcnt;

         void f(int & mcnt) {
           // blah blah blah

           mcnt++;

           // blah blah blah
           }

         void g(void) {
           // blah blah blah

           f(mcnt);

           // blah blah blah
           }
       }

   Similarly, the global reference to mcnt in g() can be eliminated:

     class Message {

       private:
         int mcnt;

         void f(int & mcnt) {
           // blah blah blah

           mcnt++;

           // blah blah blah
           }

         void g(ing & mcnt) {
           // blah blah blah

           f(mcnt);

           // blah blah blah
           }
       }

   Note that it now clear that the value of mcnt may change when g() is called;
   this was not at all apparent in the original version of Message.

 4 There were two test sets applied to the fourth assignment. You've already
   seen the first; here's the second:

-- File begins on the next line; delete leading '-'
-From
-Subject: The cheese stands alone.
-From: The man on the moon.
-To: Mice everywhere.
-
-Frommage: it's what's for dinner.
-
-Frommage stands alone.
-
-Frommage and crackers
-- File ends on the previous line; delete leading '-'

   Here's an example of a successful test:

     spawn readmbox ../../test-mbox-4.2
     There is 1 message.
     * 1
     Frommage: it's what's for dinner.

     Frommage stands alone.

     Frommage and crackers
     * q



This archive was generated by hypermail 2.0b3 on Fri Aug 11 2000 - 15:25:05 EDT