CS 228 meeting -*- Outline -*- * design of ADT operations (HR 9.2) ** overview (p. 390) ------------------------------------------ OVERVIEW OF ADT DESIGN PROCESS Steps involved: 1. describe (model) the abstract values 2. select and specify the operations 3. evaluate for completeness, simplicity ------------------------------------------ completeness means you can do essentially anything useful, perhaps by programming simplicity means it's easy to understand ** examples *** immutable Ratl type ------------------------------------------ DESIGN OF RATIONAL NUMBER TYPES Ratl 1. model is ___________________________ 2. operations class Ratl { public: Ratl(int n, int d); // PRE: d != 0 // MODIFIES: self // POST: self = (n/d) int numr() const; // POST: FCTVAL == numerator of self int denr() const; // POST: FCTVAL == denominator of self #include "Ratl.pri" }; ------------------------------------------ ... mathematical fractions with numerator and denominator Q: What is being hidden by this type? the ability to mutate The objects of such a type are ... ------------------------------------------ def: a ADT has *immutable objects* iff the abstract value of the object ------------------------------------------ ... can't be changed once the object is created. Often useful for mathematical, or atomic ideas (numbers); unusual for ADTs that are collections. Q: Is Ratl simple? Q: Is Ratl complete? Q: What kinds of things might we want to do? (make a list) I/O algebraic, more generally: construction of new based on old (+, -, *, ...) observations ( ==, !=, <, etc.) Q: Can you program these as a client of Ratl? if yes, then it's complete, so it's complete Note that nothing prevents the constructor from simplifying the fraction. Q: What if we didn't have the denr function, would it be complete? if didn't have both numr and denr, then all objects would look the same to clients *** immutable Fraction type (more operations) Tradeoff between simplicity and utility: the client has to write more with Ratl ------------------------------------------ A "FULL-FEATURED" TYPE DESIGN class Fraction { public: // C++ constructors (primitive) Fraction(); Fraction(int i); Fraction(int n, int d); // ADT-constructors (non-primitive) Fraction operator +(Fraction oth) const; Fraction operator -(Fraction oth) const; // etc. // observers int numr() const; int denr() const; double DoubleEquiv() const; Boolean operator ==(Fraction oth) const; Boolean operator < (Fraction oth) const; // etc. #include "Fraction.pri" }; ostream& operator << (ostream& out, Fraction f); ------------------------------------------ compare to FracType in book, this one is still immutable *** set types ------------------------------------------ MUTABLE OBJECTS def: a ADT has *mutable objects* iff the abstract value of the objects ------------------------------------------ ... can be changed over time by the operations ------------------------------------------ KINDS OF OPERATIONS FOR TYPES WITH MUTABLE OBJECTS - C++ constructors (primitive) - a C++ destructor - ADT-constructors (non-primitive) - observers - mutators e.g., Delete from an IntSet operator = ------------------------------------------ non-primitive constructors are somewhat rarer for mutable objects mutators important Note, the HR book lumps together mutators and ADT-constructors, I think that's confusing The HR book splits (p. 394) observers into: type conversion functions test operations including finiteness ops (IsFull) selector operations (get part of the value) It also makes a special case for assignment and copy operations Should also note I/O, even though it's outside of a class itself Q: Where does the assignment operator fit in? The copy constructor? ------------------------------------------ FOR YOU TO DO (In groups of 3 or 4) A first step in the design of an ADT for sets of Integers. Use mathematical sets as the model. List operations in two parts: (a) a minimal, but complete set (b) others for a "full-featured" set Also, write down any functions that (c) should be implemented as client code. Write down both a name and a prototype for each operation and function. ------------------------------------------ Say not to be limited by what's in the book Then make a list of these on the board An example for (c) is adding the element 1 to a set. This will give the opportunity to talk about completeness for types with mutable objects like this A problem with Set as specified in the book, is that there's no way to get at the elements. If time, specify some of these ** completeness (HR pp. 394-5) this should be thought of as a design heuristic, not as a rule there will be exceptions... ------------------------------------------ COMPLETENESS FOR ADTS def: Let T be an ADT with domain D. The design of T is *complete* iff: 1. For each abstract value v in D, a client can construct an object with abstract value v. 2. A client can program any computable function on ------------------------------------------ ... the abstract values. this means you can extract all the information in the value. ------------------------------------------ 3. If T has mutators, then ------------------------------------------ ... a client can modify any given object of type T to have any given abstract value. Draw picture: client capabilities =======ADT barrier========= representation capabilities One way to think of this is that generally don't want to hide the computational power of the rep, instead the idea is to make it more convenient for the client Counterexamples to (1): set without any way to make an empty set (no Delete operation, no default constructor) Q: Does set have enough constructors? but how do you make the set {3,4,5}? Counterexamples to (2): IntSet without any way to test for existence of elements Almost a counterexample to (2), and one in practice: IntSet without any way to get a random element and delete it. def: an ADT design is effectively complete if any computable function can be programmed, even if the domain is assumed infinite. Counterexamples to (3): suppose you could only insert elements, but not delete them Caveat, sometimes you don't want ADTs to be complete in this sense (esp. for property 3), but usually you do. Sometimes the domain D is taken to be larger than needed, just to make the task of specification easier (e.g., allow infinite sets, or arbitrarily large integers) ------------------------------------------ TESTABILITY def: an ADT has testable preconditions if the veracity of each precondition in its specifiction ------------------------------------------ ... can be decided by a client program, for each object of the type. Caveats: sometimes, it's just as easy to make a condition happen as to provide a way to test for it e.g., Simplify in the HR book's FracType This is why I don't specify that a parameter is "assigned", as it can't be tested (HR say it doesn't need to be...)