TITLE: Procedural vs Object-oriented programming PROBLEM: tmb@arolla.idiap.ch (Thomas M. Breuel) You don't have to pray if you have a compiler with good compile-time diagnostics and if you define your classes better: enum ShapeType {ShapeCircle, ShapeTriangle, ShapeSquare}; struct Shape { enum ShapeType type; }; s = ... some shape ... switch(s->type) { case ShapeCircle: ... break; case ShapeTriangle: ... break; case ShapeSquare: ... break; } In this case, GNU C (and probably other compilers) will warn you about each switch statement that lacks a case for a new shape type if another shape type is added to the enum ShapeType. So, we really have three different mechanisms for handling the "self-identification" problem: (1) virtual functions (2) enumerated type identifiers (as in the above example) (3) RTTI Each of those has its place. Both (1) and (2) can ensure that you don't accidentally add a new class or type without updating all the dispatch tables. Whether (1) or (2) is better depends very much on the kind of problem you are looking at. If you expect that you will be adding lots of new classes as the program evolves, then (1) is probably a better choice. If you expect that you will be adding lots of new functions/methods as the program evolves, then (2) is probably better, even if the support for it in C++ is pretty weak. RESPONSE: rmartin@rcmcon.com (Robert Martin), 16 Dec 93 However, in this example, adding a new ShapeType forces you to recompile and retest Shape, and all of the clients of Shape. Something to be avoided if at all possible. Also, (1) is guaranteed by the language to catch the addition of new types. If you add a new type and do not implement the necessary pure virtual functions, then the compiler will refuse to compile the code. (2) makes no such guarantees, although it is possible to find compilers that will elicit the appropriate warnings. There is a symmetry between OO and procedural programming (PP . The symmetry is a type/function symmetry. In general, whatever is true for functions in OO, is true for data types in PP. In PP new functions can be added without affecting the existing data types. In OO new data types can be added without affecting the existing functions. In PP the addition of a new data type causes changes to all the client functions. In OO the addition of a function causes changes to all the client data types. However, the symmetry is not perfect. There exist statements which are true for OO but whose converse is not true for PP. One such statement is: A function can pass a data type to another function without any dependency upon the definition of that data type. Another is: A function can call another function without any dependency upon the definition of the function being called. One might refute that PP can pass anonymous data structures by using various forms of casts and common data elements, but this is a contrivance which approximates OO. One might refute that PP can call anonymous functions by using pointers to functions that get loaded at run time, but this again is a contrivance which approximates OO. When one does not employ OO, or the contrivances mentioned above, and relies on PP only, then one has lost the ability to pass anonymous data structures and call anonymous functions. These abilities are important because they allow the dependencies between functions to be turned upside down. In PP, high level functions depend upon low level functions. But in OO, high level functions (in abstract base classes) are independent, and low level functions depend upon them (through inheritance). This inverse functional dependency cannot be achieved in PP without reliance upon the above mentioned contrivances. In PP function depends upon data. If data structures are changed, the functions that maniuplate them must be changed. However the data structures themselves are independent. e.g. a database schema can accomodate many different kinds of applications. In OO, function still depends upon data, but it is also possible to force detailed functions to depend upon high level functions. This allows the high level policy decisions to be independent and reusable. e.g. a given high level independent structure can accomodate many different kinds of applications. My point is that if you have an application in which you will be adding lots of functions, you may still be better off using OO.