If for each object o1 of type S there is another object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.Barbara Liskov, "Data Abstraction and Hierarchy," SIGPLAN Notices, 23,5 (May 1988)
see also
If type T denotes a set of values that carry their own behavior, and
if values of type S can override some of T values behavior, the LSP is
undecidable. Indeed, a mechanical application of LSP must at
least be able to verify that all methods overridden in S terminate
whenever the corresponding methods in T terminate. This is generally
impossible.
On the other hand, if T denotes a set of (structured) data values, and
S is a subset of these values -- e.g., restricted by range, parity,
etc. -- the LSP is trivially satisfied.
W.R. Cook, W.L.Hill, P.S. Canning, "Inheritance Is Not Subtyping," In: Carl A. Gunter and John C. Mitchell. Theoretical Aspects of Object- Oriented Programming. MIT Press. ISBN 0-262-07155-X.
Sidebar: "Inheritance: Structural or Behavioral Conformity?"
In: "Executable Object Modeling with Statecharts,"
David Harel and Eran Gery,
IEEE Computer, Vol. 30, No. 7, July 1997, pp. 31-42.
Luca Cardelli, P. Wegner, "On Understanding Types, Data Abstraction, and Polymorphism," ACM Comp. Surveys, 17(4):471-522, Dec. 1985
see also
Date, C., Darwen, H, Foundations for Object/Relational Databases,
Addison-Wesley, 1998.
However, the bottom line is that these techniques [templates and overloading] allow you to write efficient, type-safe, and generic code. People familiar with functional languages will note that these techniques are similar to techniques pioneered in those languages.Bjarne Stroustrup, "The Real Stroustrup Interview", IEEE Computer, vol. 31, No. 6, June 1998, pp. 110-114.
...However, not every concept naturally and usefully fits into a hierarchy, not every relationship among concepts is hierarchical, and not every problem is best approached with a primary focus on objects. For example, some problems really are primarily algorithmic. Consequently, a general-purpose programming language should support a variety of ways of thinking and a variety of programming styles. This variety results from the diversity of problems to be solved and the many ways of solving them. C++ supports a variety of programming styles and is therefore more appropriately called a multiparadigm, rather than an object-oriented, language (assuming you need a fancy label).
Examples of designs that meet most of the criteria for "goodness" (easy to understand, flexible, efficient) are a recursive descent parser, which is traditional procedural code. Another example is the STL, which is a generic library of containers and algorithms depending crucially on both traditional procedural code and on parametric polymorphism.
I find languages that support just one programming paradigm constraining. They buy their simplicity (whether real or imagined) by putting programmers into an intellectual straitjacket or by pushing complexity from the language into the applications. This is appropriate for special-purpose languages, but not for general-purpose languages.
Another problem with OO languages is their emphasis on inheritance. Implementation inheritance, in which one class borrows code that was written for another class, is a bad idea that makes software harder to manage and reuse. It binds the implementations of classes together so that neither class can be understood without the other. A subclass cannot be understood without knowing how the inherited methods are implemented in its superclass, and a superclass cannot be understood without knowing how its methods are inherited in subclasses. In a complex class hierarchy, no individual class can be understood without understanding all the other classes in the hierarchy. Even worse, a class cannot be separated from its hierarchy for reuse. Multiple inheritance makes these problems even worse. Implementation inheritance causes the same intertwining and brittleness that have been observed when goto statements are overused.John K. Ousterhout, "Scripting: Higher-Level Programming for the 21st Century", IEEE Computer, March 1998, pp. 23-30.
Inheritance means that in order to understand the behaviour of one object, I have to understand the behaviour of all its ancestors first.Roger Peppe <rog-at-vitanuova.com>. Originally appeared in an IT Forum Plan 9/Inferno Programming. Quoted by permission.Inheritance means that one is never quite sure whether it's appropriate to call a method defined in a superclass, for fear that it won't interact correctly with the intended use of the object. Inheritance means that if I want to change the superclass of an object, I probably can't, as there will be a host of other modules that have come to rely on methods specific to its ancestors. Inheritance means that my program might raise a type-error exception at some unexpected moment.
And most importantly (in my view), inheritance makes for programs that are almost unreadable. What does the following Java class do?
class MyClass extends AnotherClass { public boolean aMethod() { return true; } }The answer is: it's impossible to tell without looking at all its superclasses. It might be overriding
aMethod
inAnotherClass
, which might subtly alter the progress of some algorithm implemented byAnotherClass
. Or perhaps some other object might dynamically check for the presence ofaMethod
and check its value if so. But without excellent documentation (not likely!) or access to all the source code, that code is completely opaque. The function of the code accomplished is by implication rather than by action [emphasis added]. And in my experience, a lot of OO code looks very similar to the above. Write some code, cross your fingers and hope it gets called...
The point made in two previous quotations receives a surprising corroboration, from a staunch C/C++ programmer. In his regular "C Programming" column in December 2000 issue of Dr.Dobb's Journal (Quincy 2000: Customizing the Print Dialogs, pp. 129-139), contributing editor Al Stevens describes tribulations of making a simple change in a OO (MFC) program. The whole article is well worth reading. Its conclusion offers a rather surprising advice:
Between getting the button installed, integrating the dialog, and fixing the phantom checkbox gotcha, I had a lot of false starts and made a lot of false turns during what ought to have been a simple job -- adding a checkbox to a dialog.... All the books that promise in their titles and on their back covers to reveal so-called secrets of Win32 MFC programming reveal very few actual secrets. Mostly what they do is explain how to write programs that stay within the boundaries that the designers of the Win32 API and MFC assumed you could live with. Usually I find those boundaries pertain only to the most trivial of applications, which is what books tend to use as examples, anyway. But when you want to push the envelope, break the bonds of convention, and escape those boundaries, forget the books. Your best bet is to trace the MFC source code and see what it's doing.To add a simple checkbox to the standard MFC
PrintDialog
Al Stevens indeed had to examine -- reverse
engineer, to be precise -- a large portion of the MFC code that deals
with instantiating and operating PrintDialogs.
See also
This and the next article put OOP claims to an experimental test. The
proponents of OO argue that OO paradigm helps writing good
software. The total time to develop an application that passes quality
controls, the number and the rate of defects, the amount of time it
takes to fix them -- are all measurable quantities. There should
therefore be possible to experimentally compare OOP with alternative
methodologies.
Granted, there is no such person as an "average programmer". By the
same token, there is no "average patient". Response of each individual
to a drug is unique. Nonetheless there are standard techniques --
clinical trials and statistical methods -- that can ascertain with
confidence if a particular drug is effective in fighting a particular
disease. Similar testing techniques can be applied to software
engineering.
This and the following article report on such tests. They found out
that OOP, compared to other methodologies, hurts rather than helps
programmer's productivity. This is an experimental result.
Remark: Basically the biggest difficulty with OO is
inheritance, especially implementation inheritance. Overriding and
extending behavior requires a programmer to determine and keep in mind
all the various ways a parent object may be used. This requirement
may stretch human capacity. Humans can hold in their short-term
memory roughly 7 pieces of information.
Remark: Furthermore, most of the OO languages are not faithful to the OO concept. For example, an object is usually an instance of a class. That is, an object cannot change its class during a lifetime. Consider an object representing a person. Consider classes 'persons under 21 years of age' and 'adults'. An object of an underage class cannot later become an adult. The underage object needs to be destroyed and an 'adult' class object instantiated. So much for the claim that OOP accurately models reality: on his 21st birthday, some capacities of the person surely change; yet a person at the age 21 +1 day remains basically the same person (character, name, color of eyes, names of the parents, school attending, etc) as he was at the age 21 -1 day.
The paper reports the results of essentially an opinion poll, which found that the majority of 150 polled software developers think highly of OOP. However, the very same paper says, "while opinions concerning the benefits of OOSD [Object-Oriented Software Development] abound in OO literature, there is little empirical proof of its superiority." Is OOP an article of faith then?
The article explains well-known theoretical problems with OOP (e.g., the "yo-yo" trouble). The thrust of the paper however is on productivity failure and on the reluctance of OOP proponents to back their enthusiasm with hard, empirical data.
"Numerous articles have been published in many periodicals, from IEEE Software and ACM journals, to Business Week and the Wall Street Journal. Mountains of PR suggest the great productivity improvements we could expect from OOP technology. Every programmer concerned about this technology learned to embrace this view. The truth is, the productivity improvements never happened. In fact, studies have shown software productivity as a whole has been in a decline for more than a decade. The five years prior to 1996 (the heydays of OOP), a period of general growth, software productivity was negative, more negative than any other industry [2]."
..."What is most interesting is that no one appears to be talking in terms of productivity (for an exception, see [1]). They are all lost in the mazes of theoretical beauty of their creations. According to quality control expert Deming, if you can't measure it, you can't improve it. So why is it so difficult to bring computer science into the world of hard science and to start measuring the real results of some of these hypotheses?"
"Cypher and Smith (1995) found in user studies that inheritance hierarchies cause difficulty for children. Even among professional programmers, researchers have found that full-edged object-oriented programming is not necessarily natural (Deetienne, 1990; Glass, 1995)."
OOP is often considered a module system: a class is a namespace for its members. As the paper notes, "If a module provides just one abstract type X, and the types of all the operations have the form X -> T or T -> X (with X not in T), then we can re-organize the module as an object." The paper goes on to explain that OOP as a module system cannot express generic inter-module references, which matter in some real examples.
"In a real-world example, a 2004 study [the above citation] suggested that the separation of data and actions -- contrary to the philosophy of the OO paradigm -- may be better suited to many business applications than other problem-solving paradigms." Quoted from Chenglie Hu, "Dataless objects considered harmful". Comm. ACM, v48, No. 2, pp. 99-101, Feb 2005.
Brian McNamara and Yannis Smaragdakis,
http://www.cc.gatech.edu/~yannis/fc++/
oleg-at-okmij.org