18

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?

  • 3
    Interesting question! I have the feeling that the answer is going to be somehow related to the fundamental difference between Abstract Data Types and Object-Oriented Data Abstraction, which are the two dominant data abstraction mechanisms in Modular Programming (what Betrand Meyer is referring to as "classical approaches") and Object-Oriented Programming (read the comments!), respectively. – Jörg W Mittag Oct 2 '15 at 22:25
  • That is strange. It seems blatantly contradicted by reality (even in 1988). Also, his advocated approach would result in an unhelpful proliferation of modules. – user82096 Oct 3 '15 at 8:47
  • @dan1111: Eiffel's approach to inheritance, including, but not limited to its approach to multiple inheritance is different from C++, Java, C#, etc., so it's not surprising that the approach is different. He developed Eiffel specifically to support his views on OO, after all. – Jörg W Mittag Oct 3 '15 at 17:43
17

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.

  • Interesting, and I'll definitely have to try to get ahold of the second edition, but it's still not clear to me why even a non-OO "classical" library couldn't add (at least certain kinds of) features without disturbing its clients. – David Moles Oct 5 '15 at 16:28
  • @DavidMoles thing is, it could, and last part of my answer explains that, and that Meyer himself realised that (when he reworked for 2nd Edition) and even gave examples of how it can be done. "As for what specifically made author change their mind..." etc – gnat Oct 5 '15 at 16:50
  • Hmm. I don't see "version 2 of this library, which replaces version 1 and is backwards compatible with it, adds the following functions…" as "inheritance" except in the broadest possible conceptual way. – David Moles Oct 5 '15 at 17:31
  • (Inheritance, to me, implies that version 1 is still around and called by version 2.) – David Moles Oct 5 '15 at 17:32
  • @DavidMoles replace with version 2 (as in, change source code and recompile) wouldn't qualify as "closed for modification", you can simply check this in Wikipedia article: "entity can allow its behaviour to be extended without modifying its source code..." – gnat Oct 5 '15 at 17:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.