Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!clyde!uunet!odi!dlw From: dlw@odi.com (Dan Weinreb) Newsgroups: comp.lang.c++ Subject: Re: Design Problem Message-ID: <1989Dec5.055058.26635@odi.com> Date: 5 Dec 89 05:50:58 GMT References: <22137@brunix.UUCP> Reply-To: dlw@odi.com Organization: Object Design, Inc. Lines: 72 In-Reply-To: sdm@cs.brown.edu's message of 3 Dec 89 21:23:29 GMT In article <22137@brunix.UUCP> sdm@cs.brown.edu (Scott Meyers) writes: I'm having trouble figuring out how to solve the following problem. Often I find myself with a collection of objects of a given type, where some of them define a particular function and some of them don't, and I want to invoke the function on only those objects for which it is defined. I believe that your analysis is completely correct: the options are as you have stated them. In my own personal understanding of the philosophy behind C++, approach 1 is the recommended course. (That is, it's just my humble opinion. Approach 2 strikes me as clumsier than approach 1, and approach 3 throws the baby out with the bathwater.) In OO languages in which variables are not typed, such as Smalltalk-80 and Lisp-with-Flavors/CLOS, you wouldn't have any problem. In fact, "old Flavors" had a message called :SEND-IF-HANDLED, which was used for exactly the kind of purpose you describe. There are equivalent ways to do this in new Flavors, CLOS, and Smalltalk-80. In these languages, only the objects themselves have types, and you can just check at runtime whether an operation is handled. I spent many years programming with Flavors; this little trick is rarely used, but every once in a while it comes in quite handy. In C++, though, there is a principle that says that for every variable (every expression, really), there is a type that is lexically apparent (i.e. it can be known at compile time), and the type specifies the exact set of function members that can be called for that object. C++ has lexically-apparent typing; the meaning of "type" is (or "includes", anyway) "what operations can be done on this thing". None of these designs is attractive. The first one doesn't extend well to situations in which there may be many functions like evaluate() down in the hierarchy -- each will have to be defined in ARC, even though they have nothing to do with generic ARCness. Well, from the point of view of C++ philosophy (IMHO), they sort of *do* have something to do with ARCness because you call these functions on ARCs of all sorts, executable and not-executable. This is the key point. In addition, it suffers from the same problem that the second one does: adding new classes to the hierarchy may require that I modify the base class (e.g., adding new enumerated type values). That's because the base class does *two* things in C++: it defines a particular class, and it defines a "protocol" for a family of classes. I am using the word "protocol" in the sense in which it is used by the Smalltalk-80 people; roughly, a definition of a set of messages, their names and arguments, independent of the classes that provide methods for those messages (if I may be allowed to use the Smalltalk lingo for one sentence). Adding a new operation changes the protocol, so you have to redefine the base class. You could look at it as a tradeoff. The C++ style of typed variables provides you with extra checking; but you have to do extra work while programming in exchange. There are similar tradeoffs to be found in comparisons of the typed-variable and untyped-variable languages. Actually, if I were programming in Flavors and were trying to do precisely what you are trying to do, I would define a default method on the base class. It seems to me more stylistically desirable, probably because the send-if-handles thing is more powerful than necessary; if my program accidentally did one of these operations to a non-ARC, I'd like an exception to be signalled at runtime. That's another way that these operations might really be said to have something to do with ARCness. So what I'm trying to say is that maybe your approach 1 isn't really so bad after all. Dan Weinreb Object Design, Inc. dlw@odi.com