20

In Meyer's Object-Oriented Software Construction (1988) he defines the open/closed principle as follows:

  • A module will be said to be open if it is still available for extension. For example, it should be possible to add fields to the data structures it contains, or new elements to the set of functions it performs.
  • A module will be said to be closed if it is available for use by other modules. This assumes that the module has been given a well-defined, stable description (the interface in the sense of information hiding).

He goes on to say:

If you reopen a module, you must also reopen all its clients to update them, since they rely on the old version. … [This problem] arises every time a module must be extended by a new function or data element, triggering changes in direct and indirect clients. ... With classical approaches to design and programming, there is no way to write modules that are both open and closed.

Meyer's solution to this dilemma is: never extend a library module by modifying existing classes; instead, write a new module that subclasses the existing classes, and have new clients depend on that new module.

Now, in 1988, I was was writing toy (procedural) programs in Turbo Pascal and Blankenship Basic, and my 21st-century professional experience is on the JVM, the CLR, and in dynamic languages, so I don't know what Meyer meant by "classical approaches to design and programming".

Meyer's one concrete example of why client modules must be reopened (a switch statement on an enumeration which now has more members, requiring more cases) seems reasonable enough, but he doesn't nearly justify the assertion that every time you add functionality to a library module, you need to update all its clients.

Is there a historical reason that this assertion seemed self-evident in 1988? Did, say, adding functions or data structures to a C static library change the layout such that even with backwards-compatible APIs, clients had to be recompiled? Or is Meyer really just talking around a mechanism for enforcing API backwards compatibility?

Doc Brown
  • 218,378

1 Answers1

18

As far as I can tell, this question has been answered by Bertrand Meyer himself, and the answer is, this statement is not accurate. With classical approaches to design and programming, there indeed can be a way to write modules that are both open and closed.

To find this out, you need to study second edition of this book (published nine years later, in 1997). According to Foreword to the second edition, it is

not an update but the result of a thorough reworking. Not a paragraph of the original version has been left untouched. (Hardly a single line, actually.)

In particular, the statement that confuses you has gone. There still is Open-Closed principle chapter in "§3.3 Five Principles", and there is further thorough discussion of this topic in "§14.7 Introduction To Inheritance" but the statement from first edition isn't there anymore.

What is there instead focuses on how it is more convenient and idiomatic in OO approach as opposed to prior ways,

Thanks to inheritance, O-O developers can adopt a much more incremental approach to software development than used to be possible with earlier methods...(§3.3)

This double requirement (open and closed) looks like a dilemma, and classical module structures offer no clue. But inheritance solves it. A class is closed, since it may be compiled, stored in a library, baselined, and used by client classes. But it is also open, since any new class may use it as a parent, adding new features and redeclaring inherited features; in this process there is no need to change the original or to disturb its clients... (§14.7)

Since you also seem to wonder about what "classical approaches" Meyer meant here, you can find explanation of these in §4.7 Traditional Modular Structures. This section explains that these mean "libraries of routines" and "packages" (for the latter, author says the term is taken from Ada and mentions other languages having this feature - clusters in CLU and modules in Modula).

If you think of it, none of these approaches was originally intended to aid in writing code that adheres to open-closed principle. This could lead author to their somewhat premature assessment that was later corrected in second edition.


As for what specifically made author change their mind on that statement in between first and second edition, I think one can find an answer, again, in the book itself, namely in Part F: Applying the method in various languages and environments". In this chapter, author discusses how object oriented methods can be used in older languages:

Classical languages such as Fortran are not O-O at all, but people who must still use them... may want to apply as many O-O ideas as feasible within the limitations of these older approaches.

In particular, in this part Meyer explains in details how it would be possible to implement inheritance (with some caveats and limitations, but still) in C and even in Fortran.

You see, this really calls for revising that statement from first edition. It seems practically impossible to explain how to reconcile "with classical approaches... there is no way" with realistic examples on how exactly it can be done.

gnat
  • 20,543
  • 29
  • 115
  • 306