Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!sun-barr!olivea!uunet!stanford.edu!neon.Stanford.EDU!news From: philip@pescadero.stanford.edu (Philip Machanick) Newsgroups: comp.object Subject: Re: Readability of Ada Message-ID: <1991Apr27.012355.29911@neon.Stanford.EDU> Date: 27 Apr 91 01:23:55 GMT References: <3878@ssc-bee.ssc-vax.UUCP> <20245@alice.att.com> <1991Apr23.193715.23815@odin.diku.dk> <1991Apr25.170356.21237@odin.diku.dk> Sender: news@neon.Stanford.EDU (USENET News System) Organization: Computer Science Department, Stanford University Lines: 84 In article jls@rutabaga.Rational.COM (Jim Showalter) writes: >>Apparently, while arguing *against* the usefulness of inheritance, > >I did no such thing. I merely asked how to do a simple thing in C++. >The answer, so far, is "Uh, well, that's not one of the things you >can do easily in C++." OK, so how easily _can_ this be done in C++? For anyone who's lost track, the original example was Consider the shapes example. Suppose that the given example goes out in binary form, and arrives at my site, and I want to add a new shape. Suppose that the initial shapes were limited to triangles and squares. Suppose that I now add a Circle, which has a new method defined for it that does NOT apply to triangles or squares and which was never previously defined in the base class for shapes--radius. This method returns the radius as some floating point number from 0 to whatever. (I used integers to save typing - ignore the details). Now, I want to take a heterogeneous list of shapes, including triangles, circles, and squares, and I want to iterate over the list and print out all of the radii. How do I do this? I can't get elements out of the list and call the Radius method on all of them, because not all of them HAVE such a method defined. I can't add the new method to the base class (with a null implementation as the default for those shapes for which it is a meaningless operation) because the base class is in binary. I can't ask the shapes to tell me their Kind because there is no such operation defined on them in C++. It is my claim that solving this problem in C++ results in a solution that is every bit as messy as simply using a discriminated record and an enumeration type in Ada--and Ada doesn't HAVE inheritance. My solution is reasonably simple, if not as clean as I'd like. I wrap a new class "gen_shape" around the "library" class "shape", with inlined calls to all the methods in shape. I then add a new method (member function in C++), which computes the radius. As a bonus, I include an enumerated type giving names to all the shape types, so I can distinguish between them. Here's some detail: -- #include "Shapes.h" /* the header for the library */ class circle : public shape {public: // assume we can compute this from data common to other shapes int get_radius (); }; enum shape_type {triangular, circular}; // plus others in package // extend the provided shape class to do what we want // note that the redefined methods do not need to be virtual, as the // call to the contained object will be via the virtual function table class gen_shape {public: gen_shape (int length, int width, int height, int x_pos, int y_pos); void draw () {the_shape->draw ();} // plus the same for the rest of the class ..... // added for circles int get_radius (); protected: shape *the_shape; shape_type kind; }; // and here's how radius is implemented int gen_shape :: get_radius () { if (kind == circular) return ((circle*) the_shape)->get_radius (); else return the_shape->get_height () / 2; // or whatever makes sense } -- This is slightly clumsy, and requires merging some of the supplied library header file with your own code, but perhaps not as bad as one might expect. The "default" case is still handled simply (using inheritance), and only the "exception" requires a patchy workaround. I think this is in the spirit of good language design: handle the common case well. Could you do better in Ada? Philip Machanick