(written by lawrence krubner, however indented passages are often quotes). You can contact lawrence at: lawrence@krubner.com, or follow me on Twitter.

The No True Scotsman fallacy leads to arguments like this:

Person A: “No Scotsman ever steals.”

Person B: “I know of a Scotsman who stole.”

Person A: “No True Scotsman would ever steal.”

Person A is thus protected from the harmful effects of new information. New information is dangerous, as it might cause someone to change their mind. New information can be rendered safe simply by declaring it to be invalid. Person A believes all Scotsman are brave and honorable, and you can not convince them otherwise, for any counter-example you bring up is of some degraded Untrue Scotsman, which has no bearing on whatever they think of True Scotsman. And this is my experience whenever I argue against Object Oriented Programming (OOP): no matter what evidence I bring up for consideration, it is dismissed as irrelevant. If I complain that Java is verbose, I’m told that True OOP Programmers let the IDE take care of some of the boilerplate, or perhaps I am told that Scala is better. If I complain that Scala involves too much ceremony, I’m told that Ruby lacks ceremony. If I complain about the dangers of monkey-patching in Ruby, I’m told that True OOP Programmers know how to use the meta-programming to their advantage, and if I can’t do it then I am simply incompetent. I should use a language that is more pure, or a language that is more practical, I should use a language that has compile-time static data-type checking, or I should use a language that gives me the freedom of dynamic typing. If I complain about bugginess, I’m told that those specific bugs have been fixed in the new version, why haven’t I upgraded, or I’m told there is a common workaround, and I’m an idiot if I didn’t know about it. If I complain that the most popular framework is bloated, I’m told that no one uses that framework any more. No True OOP Programmer ever does whatever it is that I’m complaining about.

There are many beautiful ideas that people associate with OOP. I am going to show 2 things:

1.) compared to other languages (lisps, functional languages, etc) OOP languages have no unique strengths

2.) compared to other languages (lisps, functional languages, etc) OOP languages inflict a heavy burden of unneeded complexity

Those features which are potentially good (data hiding, contract enforcement, polymorphism) are not unique to OOP and, in fact, stronger versions of these things are available in non-OOP languages. Those features that are unique to OOP (dependency injection, instantiation) are awful and exist only because OOP is awful.

I am taking an ecumenical, universalist approach to OOP. Below I will refer to all of these languages as OOP: C++, Java, Scala, PHP, Ruby, and Javascript. Is that fair? I know, from personal experience, some proponents of Java will complain that Ruby and PHP lack compile time data-type checking and therefore should not be considered OOP. And I know, from personal experience, some proponents of Ruby will argue that in Ruby everything is an object, whereas Java still has non-object primitives (such as integers), and therefore Ruby is more of an OOP language than Java. I know that some critics of PHP will argue that OOP features were bolted on to PHP and it should not be taken seriously as an OOP language. I know some people will point out that Scala is multi-paradigm and it is as easy to work in the “functional paradigm” with Scala as it is easy to work with the object oriented paradigm.

Given the diversity of the languages, and the lack of a standard definition, is it meaningful to talk about OOP at all? I would say yes. The need is urgent. OOP may be a poorly defined, amorphous concept, but it absolutely dominates the tech industry. Many software developers, and many companies, feel that OOP is the only reasonable way to develop software today. Any one who argues against OOP is immediately made conscious of the fact that they are arguing against the “conventional wisdom” of the industry.

I run into this when I go to a job interview. It does not matter if I interview for a Ruby job, or a Java job, or a PHP job, the job interviewers ask me if I know what OOP is. They ask me to define “encapsulation” and “polymorphic dispatch”. These are standard questions, to which I am expected to give the standard answers. And when they ask me “What are the benefits of OOP?” I find myself wanting to give an awkwardly long answer, which consists “These are the 12 things that are supposed to be the benefits of OOP, but really OOP has no unique strengths.” And so I am writing this essay, and in the future, when I’m asked questions like this at a job interview, I’ll simply directly people to what I have written here.

Does any of this really matter? You could argue that I’m wasting my time, that I am writing a very long essay that merely engages in a bunch of semantic hair-splitting that benefits no one. But I would suggest that muddled definitions lead to muddled thinking, in the manner that Orwell described:

A man may take to drink because he feels himself to be a failure, and then fail all the more completely because he drinks. It is rather the same thing that is happening to the English language. It becomes ugly and inaccurate because our thoughts are foolish, but the slovenliness of our language makes it easier for us to have foolish thoughts. The point is that the process is reversible. Modern English, especially written English, is full of bad habits which spread by imitation and which can be avoided if one is willing to take the necessary trouble.

On that basis, I would like to think that I do some good, to the extent that I’m able to take on the broad range of ideas associated with OOP.

This essay is long, and it would be even longer if I carefully qualified every sentence about OOP. Please note that, below, when I refer to a multi-paradigm language, such as Scala, as an OOP language, I am specifically referring to the OOP qualities in that language. And I would like you to ask yourself, if you use a multi-paradigm language to write in the “functional” paradigm, are you actually gaining anything from the OOP qualities of that language? Could you perhaps achieve the same thing, more easily, using a language that is fundamentally “functional”, rather than object oriented?

On tech blogs and forums, there are a great many people who defend OOP, and who feel certain that they know what they are defending, despite the lack of any standard definition. Consider this remark by “millstone” on Hacker News:

This article, like many that cheer functional programming, falls into a certain cognitive bias, that prevents it from seeing what OO is good at.

What is OO good at? Apparently millstone thinks that OO is good at being dynamic. millstone then criticizes the fact that Haskel has static type checking, ignoring the fact that Java, C++, C# and many other OO languages all have static type checking:

Alan Kay wrote “The key in making great and growable systems is much more to design how its modules communicate rather than what their internal properties and behaviors should be.” To start to see what this means, consider the annoying String / Data.Text split in Haskell. String is very much in the “leave data alone” mindset, baring its guts as a [Char]. Now you’re stuck: you can’t change its representation, you can’t easily introduce Unicode, etc. This proved to be so rigid that an entirely new string type had to be introduced, and we’re still dealing with the fallout. Great and growable systems! The large scale structure of our software, decomposed into modules, not just at a moment frozen in time, but in the future as well. We are tasked with thinking about relationships and communication.

millstone then quotes the original article, and then makes clear they are really talking about ” truly dynamic languages” and not OOP:

To come up with a better solution [for dispatching], Haskell and Clojure take very different approaches, but both excel what any OO programmer is commonly used to. “Any OO programmer?” No way! OO as realized in truly dynamic languages exposes not just a fixed dispatch mechanism, but the machinery of dispatch itself, i.e. a metaobject protocol

There are plenty of OOP languages that have static data-type checking, and there are non-OOP languages that are dynamic, so millstone is not really talking about OOP at all, and yet millstone is certain that they know what OOP is. This is a problem that I run into fairly often: a fierce advocate of OOP who is using some idiosyncratic definition of OOP, which takes me completely off-guard.

millstone then quotes this part of an essay by Alan Kay:

Please note the irony here: millstone is quoting a passage that is critical of Java, and yet millstone is claiming this passage, about “late binding”, shows what OO is good at. By this definition, Java is not an OOP language, which would surely be a surprise to Java programmers.

Again, there are OOP languages that have don’t have late binding, and there are non-OOP languages that do have late binding. But for millstone, No True OOP Programmer would ever use a language with static data-type checking. To the extent that millstone is inventing a wholly idiosyncratic definition of OOP, their comments about OOP are wholly irrelevant to anyone else who wants to talk about OOP. And yet, in some sense, millstone is very common: I commonly run into software developers who have wholly idiosyncratic definitions of OOP. This can make it difficult to have a meaningful conversation.

How should we talk about a concept as amorphous as OOP? There is no standard definition, so the best we can do is survey a few different sources and gather up the main ideas. How should we conduct this survey? Two ways: first, a trip through history, listening to Alan Kay describe the roots of OOP, and then a look at what some current introductory materials are teaching beginners about the core ideas of OOP.

Alan Kay started with some brilliant observations about the changing nature of computing, and this fed directly into the beautiful ideas that OOP began with:

One would compute with a [laptop] “Dynabook” in a way that would not be possible on a shared mainframe; millions of potential users meant that the user interface would have to become a learning environment along the lines of Montessori and Bruner; and needs for large scope, reduction in complexity, and end-user literacy would require that data and control structures be done away with in favor of a more biological scheme of protected universal cells interacting only through messages that could mimic any desired behavior. …Somewhere in all of this, I realized that the bridge to an object-based system could be in terms of each object as a syntax directed interpreter of messages sent to it. In one fell swoop this would unify object-oriented semantics with the ideal of a completely extensible language. The mental image was one of separate computers sending requests to other computers that had to be accepted and understood by the receivers before anything could happen. In today’s terms every object would be a server offering services whose deployment and discretion depended entirely on the server’s notion of relationship with the servee.

That is a beautiful vision, but is that the same thing as what we now call “object oriented programming”? In the above quote, Alan Kay seems to be describing something close to what we would now call the Actor Model.

An actor is a process that executes a function. … Actors never share state and thus never need to compete for locks for access to shared data. Instead, actors share data by sending messages that are immutable. Immutable data cannot be modified, so reads do not require a lock. Messages are sent asynchronously and are buffered in an actor’s mailbox. A mailbox is essentially a queue with multiple producers (other actors) and a single consumer. A particular actor is driven by receiving messages from the mailbox based on pattern matching.

Alan Kay’s beautiful description of OOP bears no relation to anything that I have ever seen in the real world. Whenever I point out that what we ended up with is very far from what we were promised, I am often greeted with a No True Scotsman defense: if only I did things better, or used a purer language, then I would experience Enlightenment, and suddenly I would gain all the benefits of True Object Oriented Programming. And yet, even Alan Kay seems aware of the fact that what we ended up with is far from what he started with. He is, of course, aware that his own language, SmallTalk, never became popular. But what does he think of the languages which popularized object oriented programming?

Sun Microsystems had the right people to make Java into a first-class language, and I believe it was the Sun marketing people who rushed the thing out before it should have gotten out. …If the pros at Sun had had a chance to fix Java, the world would be a much more pleasant place. This is not secret knowledge. It’s just secret to this pop culture.

Alan Kay himself has never been a blind, ideological defender of OOP. He borrowed many ideas from Lisp, and he is open about his admiration of Lisp:

Kay characterizes SIMULA as a great transitional set of ideas. With SIMULA, Algol blocks could be used as independent things that could carry data and behavior. In 1966, Kay had just learned Sketchpad when he read an early paper on SIMULA by Nygaard and Dahl. Kay put a biological twist on what he would later call object-oriented programming. “Everything is a cell,” he explains. “The main thing I added is that everything could be an object. There is an interface algebra that today might be called polymorphism. There was a collision of these ideas and LISP.” Kay admires the great set of ideas present in LISP and refers to it as the “greatest single programming language ever designed.”

My own experience with OOP involves long meetings debating worthless trivia such as how to deal with fat model classes in Ruby On Rails, refactoring the code into smaller pieces, each piece a bit of utility code, though we were not allowed to call it utility code, because utility code is regarded as a bad thing under OOP. I have seen hyper-intelligent people waste countless hours discussing how to wire together a system of Dependency Injection that will allow us to instantiate our objects correctly. This, to me, is the great sadness of OOP: so many brilliant minds have been wasted on a useless dogma that inflicts much pain, for no benefit. And worst of all, because OOP has failed to deliver the silver bullet that ends our software woes, every year or two we are greeted with a new orthodoxy, each one promising to finally make OOP work the way it was originally promised.

Though it is meant as parody of SOAP, Peter Lacey offers what I regard as an accurate description of object oriented programming in the real world:

Dev: So it’s simple? SG: Simple as Sunday, my friend. Dev: Okay, lay it on me. SG: Well, just like it says in the name, SOAP is used for accessing remote objects. Dev: Like CORBA? SG: Exactly like CORBA, only simpler. Instead of some complex transport protocol that no one will let traverse a firewall, we use HTTP. And instead of some binary message format we use XML. Dev: I’m intrigued. Show me how it works. SG: Sure thing. First there’s the SOAP envelope. It’s pretty simple. It’s just an XML document consisting of a header and a body. And in the body you make your RPC call. Dev: So this is all about RPCs? SG: Absolutely. As I was saying, you make your RPC call by putting the method name and its arguments in the body. The method name is the outermost element and each sub-element is a parameter. And all the parameters can be typed as specified right here in Section 5 of the specification. Dev: (reads Section 5) Okay, that’s not too bad. SG: Now, when your service is deployed, you specify the endpoint. Dev: Endpoint? SG: Endpoint, the address of the service. You POST your SOAP envelope to the endpoint’s URL. Dev: What happens if I GET the endpoint’s URL? SG: Don’t know. Using GET is undefined. Dev: Hrrm. And what happens if I move the service to a different endpoint? Do I get a 301 back? SG: No. SOAP doesn’t really use HTTP response codes. Dev: So, when you said SOAP uses HTTP, what you meant to say is SOAP tunnels over HTTP. SG: Well, ‘tunnel’ is such an ugly word. We prefer to say SOAP is transport agnostic. Dev: But HTTP isn’t a transport, it’s an application protocol. Anyway, what other “transports” does SOAP support? SG: Well, officially none. But you can potentially support any of ‘em. And there’s lots of platforms that support JMS, and FTP, and SMTP. Dev: Does anyone actually use these other transports? SG: Uhm, no. But the point is you can. Dev: Fine. How ’bout this SOAPAction HTTP header, what’s that for? SG: To be honest, no one’s really sure. Dev: And these ‘actor’ and ‘mustUnderstand’ attributes, does anyone use those? SG: No. Not really. Just ignore those. Dev: All right, let me give it a shot. (time passes) Dev: Well, I could mostly make things work, but only if I stick with one SOAP stack. Also, I can’t say I like the idea of remote procedure calls and serializing objects. SG: Remote procedure calls! Serialized objects! Where did you get the impression that SOAP was about RPCs? SOAP is all about document-based message passing, my friend. Dev: But you just said — SG: Forget what I said. From here on in we pass around coarse-grained messages — you like that term, ‘coarse-grained?’ Messages that conform to an XML Schema. We call the new style Document/Literal and the old style RPC/Encoded. Dev: XML Schema? SG: Oh, it’s all the rage. Next big thing. Take a look. Dev: (Reads XML Schema spec). Saints preserve us! Alexander the Great couldn’t unravel that. SG: Don’t worry about it. Your tools will create the schema for you. Really, its all about the tooling. Dev: How are the tools gonna do that? SG: Well, they will reflect on your code (if possible) and autogenerate a compliant schema. Dev: Reflect on my code? I thought it was all about documents, not serialized objects. SG: Didn’t you hear me? It’s all about the tools. Anyway, we can’t expect you to write XML Schema and WSDL by hand. Besides, its just plumbing. You don’t need to see it. Dev: Whoa, back up. What was that word? Wizzdle? SG: Oh, haven’t I mentioned WSDL? W-S-D-L. Web Services Description Language. It’s how you specify the data types, parameter lists, operation names, transport bindings, and the endpoint URI, so that client developers can access your service. Check it out. Dev: (Reads WSDL spec). I trust that the guys who wrote this have been shot. It’s not even internally consistent.

The culture that grew up around industry standards such as WSDL lead James Lewis and Martin Fowler to complain about “a complexity that is, frankly, breathtaking“:

Certainly, many of the techniques in use in the microservice community have grown from the experiences of developers integrating services in large organisations. The Tolerant Reader pattern is an example of this. Efforts to use the web have contributed, using simple protocols is another approach derived from these experiences — a reaction away from central standards that have reached a complexity that is, frankly, breathtaking. (Any time you need an ontology to manage your ontologies you know you are in deep trouble.)

Here is an ontology to manage your ontologies (good luck!):

But of course, although umpteen millions were invested in these systems, thousands of conferences and MeetUps were held, dozens of books published, and numerous tech companies got rich as Croesus, when I bring up these expensive disasters, I am told that No True OOP Programmer does any of that nonsense any more. But of course, they do: maintaining these fragile, verbose legacy systems makes up a huge percentage of the work that OOP programmers do.

Where did Alan Kay think OOP should go?

Smalltalk is not only its syntax or the class library, it is not even about classes. I’m sorry that I long ago coined the term “objects” for this topic because it gets many people to focus on the lesser idea. The big idea is “messaging” … The key in making great and growable systems is much more to design how its modules communicate rather than what their internal properties and behaviors should be. Think of the internet – to live, it (a) has to allow many different kinds of ideas and realizations that are beyond any single standard and (b) to allow varying degrees of safe interoperability between these ideas. If you focus on just messaging – and realize that a good metasystem can late bind the various 2nd level architectures used in objects – then much of the language-, UI-, and OS based discussions on this thread are really quite moot.

Does anyone really think that OOP is the best way to give us “messaging”? We have, at this time, numerous technologies that help with messaging. An advocate of the functional paradigm might say something like “Pure functions combined with the Actor Model go much further toward giving us what Alan Kay seems to think best” but I’ll point out, you could restrict yourself to using PHP, and only use those features that were available in PHP4, back in 2004, and then add in one modern ingredient, for instance, maybe integration with ZeroMQ, and with that you would be able to achieve something closer to Alan Kay’s ideal than what most of the modern, bloated OOP frameworks give us. (Indeed, for this reason I am sad that Photon seems semi-dead, as the integration of ZeroMQ/Mongrel2 seemed like the beginning of an exciting rebirth for PHP.)

If anyone wants to respond with “but that is a completely different kind of messaging!”, that is exactly my point, that a different kind of messaging would give us something much closer to Alan Kay’s original vision: “The mental image was one of separate computers sending requests to other computers that had to be accepted and understood by the receivers before anything could happen.” Something very basic, such as PHP4 and a good networking library, would allow a kind of messaging that would naturally allow the decoupling and composability that OOP originally promised.

(In passing, let us also note that the tendency of the tech industry to re-use certain words (“message”, “class”, “hierarchy”) in radically different contexts makes it difficult for us to discuss these concepts with clarity. If we simply invented new words for new concepts, as Isaac Newton did when he invented the word “gravity”, we would have a better vocabulary for discussing the radical innovations brought to us by computers.)

When I get into a conversation with a proponent of OOP, I try to point out that the reality does not live up to Alan Kay’s original dream, at which point the original dream is usually dismissed. At this point in the conversation I typically hear some variation of “Modern OOP has evolved into something much more powerful and flexible than its original vision.” Which is fair enough. Time goes by, and software development, as a field, has undergone many changes since the early 1980s. So what are some modern understandings of OOP? Let’s review a few of the sites that try to teach OOP to beginners — what do they view as the core ideas of OOP? CodeBetter focuses on this list of features:

Encapsulation

…encapsulation is the hiding of data implementation by restricting access to accessors and mutators. Accessor

An accessor is a method that is used to ask an object about itself. In OOP, these are usually in the form of properties, which have, under normal conditions, a get method, which is an accessor method. Mutators are public methods that are used to modify the state of an object, while hiding the implementation of exactly how the data gets modified. Mutators are commonly another portion of the property discussed above, except this time its the set method that lets the caller modify the member data behind the scenes. Abstraction

Software developers use abstraction to decompose complex systems into smaller components. As development progresses, programmers know the functionality they can expect from as yet undeveloped subsystems. Thus, programmers are not burdened by considering the ways in which the implementation of later subsystesm will affect the design of earlier development. The best definition of abstraction I’ve ever read is: “An abstraction denotes the essential characteristics of an object that distinguish it from all other kinds of object and thus provide crisply defined conceptualboundaries, relative to the perspective of the viewer.” Inheritance

Objects can relate to each other with either a “has a”, “uses a” or an “is a” relationship. “Is a”is the inheritance way of object relationship. The example of this that has always stuck with me over the years is a library (I think I may have read it in something Grady Booch wrote). So, take a library, for example. A library lends more than just books, it also lends magazines, audiocassettes and microfilm. On some level, all of these items can be treated the same: All four types represent assets of the library that can be loaned out to people. However, even though the 4 types can be viewed as the same, they are not identical. A book has an ISBN and a magazine does not. And audiocassette has a play length and microfilm cannot be checked out overnight. Polymorphism

[This] manifests itself by having multiple methods all with the same name, but slighty different functionality. Many VB6ers are familiar with interface polymorphism. I’m only going to discuss polymorphism from the point of view of inheritance because this is the part that is new to many people. Because of this, it can be difficult to fully grasp the full potential of polymorphism until you get some practice with it and see exactly what happens under different scenarios.

That is fairly basic, and a bit naive. A good OOP programmer would offer some qualifiers distinguishing between best and worst practice. Wikibooks offers many of those qualifiers and therefore blunts some of my criticisms:

Object oriented programming can be traced back to a language called Simula, and in particular Simula 67, which was popular during the 1960s. It was Simula that first instituted “classes” and “objects,” leading to the term “object oriented” programming. By the early 1990s, enough experience had been gained with large OOP projects to discover some limitations. Languages such as Self, ideas like interface programming (also known as component or component-oriented programming), and methodologies such as generic programming were being developed in response to these difficulties. Although often derided by OOP purists, it was the standardization of C++ in 1998 — including generic programming facilities — that really ushered in the modern era of OOP, which we also refer to as Multi-Paradigm programming. …[offering an example about “chairs”:] …It is easy to drift off into abstruse philosophical debates over objectness; in some areas like knowledge representation and computational ontology they are very relevant. However, for a computer programmer, it is only necessary to figure out what your application needs to know about and do with chairs. …Structs (structures), records, tables, and other ways of organizing related information predated object oriented programming. You may be familiar with something like the following Pascal code: TYPE chair = RECORD

model : integer;

weight : integer;

height : integer;

color : COLOR;

END; This doesn’t actually create a chair variable, but defines what a chair variable will look like when you create one. You could proceed to create arrays of chairs and so forth, and as we hope you’ve discovered for yourself, this kind of thing is quite indispensable for keeping your programs understandable. Object oriented programming wants to push this advantage and milk it for every ounce of understandability, correctness, and simplicity it can.

When they mention “correctness” they are conflating static-typing with OOP. There are OOP languages that do not offer type enforcement (PHP, Ruby, etc). But let’s continue listening to them, because static data-types are a common argument in favor of OOP:

A fundamental problem solving technique is divide and conquer — you just have to figure out how to partition your problem into sub-problems. OOP innovators realized that we already had figured out ways to partition the problem, and it was reflected in the way we organized our data, like above. If you looked at an application that had that chair RECORD in it, you would surely find lots of code for doing things with chairs. Why else would you bother to define it? So, if you were to extract all of that code from all over the application and put it together with the chair definition, the reasoning goes, you should have an easier time ensuring that: all chair code is correct all chair code is consistent with each other there’s no duplicated chair code overall, you have less spaghetti because chair code is no longer tangled up with sofa code etc So you take that chair definition and that code extracted from all over the application, and call that a class. Take a chair variable and call it an object, and you’re off to the races.

Much of the above quote confuses OOP with static data-type checking, but there are many languages that offer type-checking without resorting to OOP. I’ll offer some examples of Haskell down below, but here I want to mention the very interesting Qi/Shen language:

Qi makes use of the logical notation of sequent calculus to define types. This type notation, under Qi’s interpretation, is actually a Turing complete language in its own right. This notation allows Qi to assign extensible type systems to Common Lisp libraries and is thought of as an extremely powerful feature of the language.

Qi/Shen has a type system that is far more powerful than anything offered by any OOP language, and yet Qi/Shen is not an OOP language. I could say the same thing about Haskell.

I have the impression that Wikibooks is doing the best that it can to defend OOP, though the writers are aware of all the many failures of OOP. And in fact, they can not think of many good things about OOP, so they instead talk about type-checking and consistency, which are available, with much less effort, in non-OOP languages. In this next quote, we can all agree that it would be bad if “Applications could easily set invalid or nonsensical values” but let’s remember that protection from invalid or nonsensical values is not unique to OOP:

Encapsulation is about risk management, reducing your maintenance burden, and limiting your exposure to vulnerabilities — especially those caused by bypassed/forgotten sanity checks or initialization procedures, or various issues that may arise due to the simple fact of the code changing in different ways over time. Technically, encapsulation is hiding internal details behind an opaque barrier so as to force external entities to interact through publicly available access points. Think about it in the context of an OS kernel, like the Linux kernel. In general, you don’t want a common user level application modifying any internal kernel data structures directly — you want applications to work through the API (Application Programming Interface). Hence encapsulation is the general term we use for giving varied levels of separation between any core system elements and any common application elements. Otherwise, “unencapsulated code” would be bad for a number of obvious reasons: 1.) Applications could easily set invalid or nonsensical values, causing the whole system to crash. Forcing the application to use the API ensures that sanity checks get run on all parameters and all data structures maintain a consistent state. Internal data structures could be updated and change (even drastically so) between seemingly minor kernel updates. Sticking to the API insulates application developers from having to rewrite their code all the time.

We should note the irony that they are using Linux to explain OOP concepts, even though Linux is written in C, which is not an OOP language. They acknowledge that OOP is not necessary for encapsulation when they write “Hence encapsulation is the general term we use for giving varied levels of separation between any core system elements and any common application elements.” They are applying this definition of encapsulation to a program written in C, so clearly, encapsulation is more about writing code intelligently than writing code with an OOP language.

As an aside, since they mention Linux, let us consider what Linus Torvalds had to say when someone suggested that Linux should be re-written with the OOP language C++:

C++ is a horrible language. It’s made more horrible by the fact that a lot of substandard programmers use it, to the point where it’s much much easier to generate total and utter crap with it. Quite frankly, even if the choice of C were to do *nothing* but keep the C++ programmers out, that in itself would be a huge reason to use C. C++ leads to really really bad design choices. You invariably start using the “nice” library features of the language like STL and Boost and other total and utter crap, that may “help” you program, but causes: – infinite amounts of pain when they don’t work (and anybody who tells me that STL and especially Boost are stable and portable is just so full of BS that it’s not even funny) – inefficient abstracted programming models where two years down the road you notice that some abstraction wasn’t very efficient, but now all your code depends on all the nice object models around it, and you cannot fix it without rewriting your app.

If you have time, you can read the conversation this sparked on Hacker News, and please note how many of the responses fall into the category of “No True Scotsman”:

Linus may be a very experienced C programmer, but that doesn’t mean his opinion on C++ carries much weight… I’d be more interested on what someone who actually has a lot of experience in using C++ says. Especially with modern C++ and recent tools, libraries etc, which are very different from what was around five or ten years ago.

A True OOP Programmer only uses the most recent tools, libraries, etc, which are very different from what was around five or ten years ago.

Linus’s objections seem centered on the fact that it makes it easier to generate bloated code. While this may be true, there’s nothing a little self-discipline can’t control.

A True OOP programmer has the self-discipline to avoid writing bloated code.

The worst accusation I can make about OOP encapsulation is that it fails to give us the protection from unwanted change that it promises us. Consider this classic example:

class UniqueId {

private i = 0;

function getUniqueId() {

return i++;

}

}

Let us assume that multiple threads are doing some work, perhaps resizing images, and to ensure a unique name for each image, they want a function that will return a unique number that they can use as part of the name. The var i is “encapsulated” because we have declared it to be private — the only way to access it is using the accessor function getUniqueId(). But sadly, it turns out that this is not an atomic operation:

i++

This is actually 3 operations:

1.) read the value from memory

2.) increment the value

3.) write the new value to memory

What happens if 2 threads call this method at the same instant? Potentially they will both get the same number returned to them — this object can not ensure that its private variable is unique.

To get around this problem, some OOP languages offer different methods of acquiring locks on objects or object fields, and some OOP languages even offer automatic ways of handling this specific problem. For instance, Java offers AtomicInteger. But AtomicInteger is a mere convenience, it simply automates, in the background, the fetching, and then the releasing, of a lock. Lot’s of non-OOP language also automate the fetching and releasing of locks (Clojure, for instance), so why should we bother with the complexity of OOP?

Whenever I make this point in conversation, someone will tell me that I am confused — locks have nothing to do with encapsulation, I am making a big mistake by running these 2 ideas together. But what is the goal of encapsulation? Encapsulation is a form of “data hiding”. Why do we want “data hiding”? We want it because we want protection from unexpected changes to state, and OOP encapsulation rarely gives us this — we have to combine this kind of encapsulation with other tools, such as locks, to achieve the goal. This suggests weakness in the way that OOP enables data hiding.

Here is one of the best passages in the Wikibooks:

Something that we don’t see reiterated enough: State (as opposed to change) is evil! Or, (perhaps better said) maintaining unnecessary state is the root of all (er… many) bugs.

No disagreement from me. This is a point that is often made by those who favor the “functional” programming style. Immutable data is safe, mutable data is unsafe. And the whole world of OOP has been moving towards favoring immutable data whenever possible. In his book “Effective Java“, Joshua Bloch makes this one of his 52 tips: favor immutable data. But then, this raises the question, why not go all the way with this, and give up OOP, and embrace the “functional” style of programming? Why not go with a language where immutable is the default and mutable is unusual?

Here is another excellent passage from the Wikibooks, about inheritance, but it again raises the question, why bother with OOP at all? We can all agree that we need our data-types to exist in a hierarchy, but we can do this more easily outside of OOP languages, so why add all the burdens of OOP?

In many books, inheritance and OOP are made to seem synonymous, so it may seem strange that we deferred this discussion so far. This is a reflection of the diminished role of inheritance over time. In fact, one of the primary distinctions between Classic and Modern OOP lies in the usage of inheritance. As the old adage goes, if all you have is a hammer, then everything looks like a nail. And so it happened that often times, inheritance was the only tool available to the erstwhile OOP programmer, and so every concept under the sun was crammed into inheritance. This lack of conceptual integrity and separation of concerns led to over-intimate dependencies and many difficulties. In some languages, programmer technique evolved to make the concepts clearer using the same limited language functions, while other languages explicitly developed features to address these concerns. Because you are almost certain to be exposed to some of this misguided advice at some point in your OOP learning, we’ll try and explain some of the problems to you. …The most over-used and rather worthless discussion on inheritance that you will see revolves around the “Is-A vs Has-A” discussion. For example, a car is-a vehicle but has-a steering wheel. The idea these authors are chasing is that your car class should inherit your vehicle class and have a steering wheel as a member. You might also run across examples with shapes, where a Rectangle is-a Shape. The point is, once again, abstraction. The goal is to identify operations that operate only on the abstract notion of vehicle or shape and then write that code only once. Then, through the magic of inheritance, you can pass in cars or rectangles or what-have-you to the generic code, and it will work, since the derived classes are everything the parent classes are, “plus more”. The problem here is that inheritance is mixing together several things: you inherit “typeness”, interface, and implementation all at the same time. However, all of the examples focus on interface while talking about “typeness”. The abstract code doesn’t care that a car “is-a” vehicle, just that the objects respond to a certain set of functions, or interface. In fact, if you want to give your chair class accelerate(), brake(), turn_left() and turn_right() methods, shouldn’t the abstract code be able to work on chairs then? Well, of course, but that doesn’t make a chair a vehicle.

I want to offer some examples from a “functional style” language, and Clojure is the functional language I know best, so I will use that. In Clojure, inheritance is simple:

(derive ::rect ::shape)

nil

(derive ::circle ::shape)

nil

(isa? ::circle ::shape)

true

(isa? ::rect ::shape)

true

Here, I get to define my data-type hierarchy independently of my functions and independently of any state. We do not need OOP to have inheritance. Someone might look at this example and complain that this, by itself, does not give us compile-time data-type checking, to which 4 responses are necessary:

1.) data-type hierarchies and compile-time checking are 2 different subjects which should be addressed separately. Some OOP languages have compile-time checking and some don’t, and some non-OOP languages have compile-time checking, and some don’t.

2.) Clojure now has a project (core.typed) that allows you to annotate your code with type checks, and the compiler issues warnings on those checks.

3.) even if you don’t use core.typed, you can use pre and post assertions on your functions which will give you run-time data-type checking

4.) don’t let the specifics of any one example distract you from the overall idea: we can have a data-type hierarchy that is independent of OOP. Please try to notice the gestalt of this essay, a gestalt that can not be communicated in any one example.

Before I sum up the supposed strengths of OOP, I will link to 2 more articles that describe the so-called strengths of OOP. Here is one from Drexel University:

Code Reuse and Recycling: Objects created for Object Oriented Programs can easily be reused in other programs. Encapsulation (part 1): Once an Object is created, knowledge of its implementation is not necessary for its use. In older programs, coders needed to understand the details of a piece of code before using it (in this or another program). Encapsulation (part 2): Objects have the ability to hide certain parts of themselves from programmers. This prevents programmers from tampering with values they shouldn’t. Additionally, the object controls how one interacts with it, preventing other kinds of errors. For example, a programmer (or another program) cannot set the width of a window to -400. Design Benefits: Large programs are very difficult to write. Object Oriented Programs force designers to go through an extensive planning phase, which makes for better designs with less flaws. In addition, once a program reaches a certain size, Object Oriented Programs are actually easier to program than non-Object Oriented ones. Software Maintenance: Programs are not disposable. Legacy code must be dealt with on a daily basis, either to be improved upon (for a new version of an existing piece of software) or made to work with newer computers and software. An Object Oriented Program is much easier to modify and maintain than a non-Object Oriented Program. So although a lot of work is spent before the program is written, less work is needed to maintain it over time.

Also, there are the SOLID principles, which describe good architectural ideas for software, and which assume that OOP programming is the best way to implement them:

Single responsibility principle

a class should have only a single responsibility (i.e. only one potential change in the software’s specification should be able to affect the specification of the class) Open/closed principle

“software entities … should be open for extension, but closed for modification.” Liskov substitution principle

“objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.” See also design by contract. Interface segregation principle

“many client-specific interfaces are better than one general-purpose interface.”[8] Dependency inversion principle

one should “Depend upon Abstractions. Do not depend upon concretions.”[8]

Dependency injection is one method of following this principle.

So, to recap, these are 12 of the things that proponents of OOP regard as the strengths of OOP:

Encapsulation

Polymorphism

Inheritance

Abstraction

Code re-use

Design Benefits

Software Maintenance

Single responsibility principle

Open/closed principle

Interface segregation principle

Dependency inversion principle

Static type checking

Some people will read this and decide that their favorite thing about OOP is not on this list. Some people will insist that the best thing about OOP is “design by contract” or testability or dependency management or some other thing that they love. This is one of the difficult things about arguing over OOP: there is a great diversity of definitions. All the same, when I go to a job interview, the things I get asked about the most often are encapsulation and polymorphic dispatch and inheritance, so simply by having those 3 on the list, I think I am covering the core ideas that people associate with OOP.

The critics of OOP have many concerns that are not on this list, for instance, object-relational impedance mismatch, and the inability of OOP to handle concurrency. And yet, even if we ignore what the critics say, we can still make clear that OOP is a terrible paradigm for writing software. (All the same, I’ll mention concurrency issues below.)

Encapsulation

I’ve already talked about encapsulation above, and I don’t have much more to say about it. OOP gives us a type of data encapsulation (that is, a type of data hiding), but it fails at the goal of protecting its “private” data from unwanted changes, as multiple threads can all read the same variable at the same instant, leading to the kinds of unpredictable changes that encapsulation is suppose to protect us from. In most OOP languages (Java, C++, etc) we only get real protection from unwanted change by acquiring a lock (that is, we only achieve the goal we are after with a combination of data hiding and locks) or some other tool of synchronization, but non-OOP languages also give us the same thing.

There are some OOP languages that are typically single threaded:

MRI Ruby

PHP

Javascript

Does OOP offer encapsulation in a single-threaded OOP language? Mostly, though in Ruby there are other ways of getting around the limits that are supposed to be imposed by the “private” or “protected” keywords. And Javascript gives us data hiding the same way any Lisp would: via closures. (Douglas Crockford was the first to show how to implement private members in Javascript by using closures.)

Whether you use an OOP language or a functional language, your enemy is state, and the goal of any kind of data-hiding is to limit the ways that state can change. John Barker sums up the enemy:

State is not your friend, state is your enemy. Changes to state make programs harder to reason about, harder to test and harder to debug. Stateful programs are harder to parallelize, and this is important in a world moving towards more units, more cores and more work. OOP languages encourage mutability, non determinism and complexity. As someone who was initially hostile to the idea that state is the root of all problems, I initially greeted this idea with skepticism. Mutating state is so easy and fundamental in OOP that you often overlook how often it happens. If you’re invoking a method on an object that’s not a getter, you’re probably mutating state.

In fact, OOP gives us a vast graph of mutable objects, all of which can mutate each other, with a change in any one object possibly setting off a cascade of mutations that propagate out through the graph in ways that are often too complicated for the human mind to comprehend. Rich Hickey (inventor of Clojure) has made this point more clearly than anyone:

Even if you don’t have concurrency, I think that large objected-oriented programs struggle with increasing complexity as you build this large object graph of mutable objects. You know, trying to understand and keep in your mind what will happen when you call a method and what will the side-effects be.

It’s also worth noting that sometimes with OOP we are forced to engage in data-hiding more than we would like, since having generic data structures, and a wealth of functions to operate on them, offers some convenience. Colin Jones sums this up nicely:

More generic data types generally have well-known and useful functions associated with them. We could enumerate the keys or values on a map, filter an array by a function, or reduce across it. Alan Perlis [allegedly] said “It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures,” and I tend to agree. One benefit of using a more generic data structure instead of hiding that data behind a class is that it removes an extra step in applying well-known functions to that data. In some situations this could be considered a downside. Consider encapsulation, where we might insulate against changes to the underlying data structures. But in many cases when choosing to encapsulate our data behind a class, the tradeoffs in ease of use and reuse are not worth it. If we decide we need encapsulation, of course, most functional languages do provide that ability using closures.

Polymorphism

Polymorphism in OOP is weak, and yet, paradoxically, polymorphism is often mentioned as a strength of OOP. Here, truly, we run into the mental weaknesses of the Blub programmer:

Programmers get very attached to their favorite languages, and I don’t want to hurt anyone’s feelings, so to explain this point I’m going to use a hypothetical language called Blub. Blub falls right in the middle of the abstractness continuum. It is not the most powerful language, but it is more powerful than Cobol or machine language. And in fact, our hypothetical Blub programmer wouldn’t use either of them. Of course he wouldn’t program in machine language. That’s what compilers are for. And as for Cobol, he doesn’t know how anyone can get anything done with it. It doesn’t even have x (Blub feature of your choice). As long as our hypothetical Blub programmer is looking down the power continuum, he knows he’s looking down. Languages less powerful than Blub are obviously less powerful, because they’re missing some feature he’s used to. But when our hypothetical Blub programmer looks in the other direction, up the power continuum, he doesn’t realize he’s looking up. What he sees are merely weird languages. He probably considers them about equivalent in power to Blub, but with all this other hairy stuff thrown in as well. Blub is good enough for him, because he thinks in Blub.

Yukihiro Matsumoto (inventor of Ruby) put the same idea in a more polite form:

Every language or system has its own culture. In the background of every language or system are some central ideas. Most of these ideas are good, but they are different. By learning many languages and systems, you get exposed to different ideas — and that enhances your point of view. If you don’t know Prolog, for example, you may not know the power of goal directed programming — programming by describing the problem to solve through specifying rules to apply. This is a very interesting concept. It is a very different way of thinking. And if you don’t know Prolog, or the predicate logic, it’s very difficult to discover this way of thinking by yourself. Knowing other systems and paradigms expands the world inside your brain. That’s why I advise learning multiple languages.

Why do we want polymorphism? Because we want flexibility in the way we dispatch execution. But OOP languages generally only give us flexible dispatch based on the signature of a method, and the signature is almost always evaluated in terms of the data-type of the parameters being handed into the method. There are more expansive ways to think of flexible dispatch. For instance, multimethods in Lisp languages give us a more powerful method of dispatch:

A Clojure multimethods is a combination of a dispatch function and one or more methods, each defining its own dispatch value. The dispatching function is called first, and returns a dispatch value. This value is then matched to the correct method. Lets take a look at our previous example refactored into a multimethod. (defmulti convert class) (defmethod convert clojure.lang.Keyword [data]

(convert (name data))) (defmethod convert java.lang.String [data]

(str “\”” data “\””)) (defmethod convert nil [data]

“null”) (defmethod convert :default [data]

(str data)) Awesome! We have our first polymorphic solution. Now we can add more data types without altering the existing functions. Let’s add a method for vectors as well. (defmethod convert clojure.lang.PersistentVector [data]

(str “[” (join “, ” (map convert data)) “]”)) Now we can also convert vectors into JSON.

In the above example, they are using “class” as the dispatch function (which returns the class of the parameter), so it works just like traditional OOP, and it even falls back on the underlying Java OOP. But we can use any function for dispatch in a multimethod.

Bozhidar Batsov offers an example using an anonymous function:

Object oriented programming in most programming languages is based on a single dispatch message passing. The object on which we invoke a method (poor choice of words, but easier to comprehend) is the receiver, the method name and it’s arguments are the message. The method’s invoked solely on the base of the type of the receiver object. Lisps have traditionally implemented OOP with generic methods, that don’t have a receiver and are dispatched on the basis of the types of all of their arguments. In the world of multiple dispatch the more traditional single dispatch is just a special case in which only the type of the first method argument matters. Here’s a taste of multimethods in Clojure: (defmulti my-add (fn [x y] (and (string? x) (string? y)))) (defmethod my-add true [x y]

(str x y)) (defmethod my-add false [x y]

(+ x y)) user=> (my-add 3 4) ; => 7 user=> (my-add “3” “4”) ; => “34” Here we defined a multi-method that behaves differently for string and numeric arguments — strings args are concatenated and numeric args are added together.

We all want the power that real polymorphism gives us, but OOP fails to deliver.

Inheritance

Inheritance is crucial to the software that I write. Inheritance is one of the most important ideas in software development. We all the want the power to create hierarchies of data types, and up above I quoted an example of how simple this can be in a language like Clojure. There is no limit to inheritance in a functional language such as Clojure, nor do complex hierarchies inflict any pain on one’s program. But in OOP programming, inheritance is dangerous:

Although introductory texts on Object Oriented Programming (OOP) are quick to tout the benefits of inheritance they typically fail to teach the lessons learned outside of academia detailing the shortcomings of this aspect of OOP. Disadvantages of using object inheritance include the following Large Inheritance Hierarchy: Overuse of inheritance can lead to inheritance hierarchies that are several levels deep. Such large inheritance hierarchies typically become difficult to manage and maintain due to the fact that the derived class is vulnerable to changes made in any of the derived classes which often leads to fragility. There are also performance considerations in that instantiating such classes involves calling constructors across the entire inheritance hierarchy as well as above average memory requirements for such objects. An example of such a class is the javax.swing.JFrame class in the Java swing library which has an inheritance depth of six levels. Fragile Superclasses: Classes that have been subclassed cannot be altered at will in subsequent versions because this may negatively impact derived classes. In C++ this is especially problematic because changes in a superclass typically end up involving a recompile of the child classes. Java utilization of dynamic resolution prevents the need for recompilation but does not entirely lessen the need to avoid making significant changes in base classes. Breaks Encapsulation: Inheritance in OOP is primarily a mechanism for reusing source code as opposed to a mechanism for reusing binary objects. This transparent nature of OOP inheritance relies on the author of the derived class being the author of the base class or having access to its implementation details. This violates one of the other tennets of Object Oriented Programming; encapsulation.

Joshua Bloch, in his book “Effective Java” says, “Favor composition over inheritance”. The problems with inheritance, in OOP, have become clearer over time. It is tragic that OOP has had to retreat from such a powerful idea, to the extent that composition is now the favored strategy:

Composition over inheritance (or Composite Reuse Principle) in object-oriented programming is a technique by which classes may achieve polymorphic behavior and code reuse by containing other classes that implement the desired functionality instead of through inheritance. Some languages, notably Go, use type composition exclusively.

It is absolutely tragic that this advice needs to be given. Back in the 1960s, OOP introduced the concept of inheritance, and yet now we know OOP is a terrible way to implement inheritance. And yet, we often want inheritance, not composition.

Inheritance is good. Nearly all data-types belong to a hierarchy, and my code should be able to represent that hierarchy without fear. If I write software for a store, I will probably have a “sell price” and a “buy price”, both of which are children of “price” which is a child of “transaction metric” which is a child of “decimal” (or “number”). I don’t want to model this with composition, nor do I want to worry about brittle base classes and tight-coupling between the interface and the implementation. To escape from these worries, I want my data-types declared in a hierarchy that is all-together separate from my code’s behavior (the functions that I write). Functional languages like such as Shen, Haskell or Clojure allow for data-type definitions that are separate from the behavior of my code. Java does not. Ruby does not. Python does not.

Consider the case where “SimpleProductManager” is a child of “ProductManager”:

public class SimpleProductManager implements ProductManager {

private List products;

public List getProducts() {

return products;

}

public void increasePrice(int percentage) {

if (products != null) {

for (Product product : products) {

double newPrice = product.getPrice().doubleValue() *

(100 + percentage)/100;

product.setPrice(newPrice);

}

}

}

public void setProducts(List products) {

this.products = products;

}

}

There are 3 behaviors here:

getProducts()

increasePrice()

setProducts()

Is there any rational reason why these 3 behaviors should be linked to the fact that in my data hierarchy I want “SimpleProductManager” to be a child of “ProductManager”? I can not think of any. I do not want the behavior of my code linked together with my definition of my data-type hierarchy, and yet in OOP I have no choice: all methods must go inside of a class, and the class declaration is also where I declare my data-type hierarchy:

public class SimpleProductManager implements ProductManager

This is a disaster.

At this point in the conversation, someone might be tempted to say something like “You can write bad code in any language, and you can write good code in any language.” That is true, but there is the question, does the language help us write good code? Does the language help with code re-use? You can adopt the functional style while still writing Java code, but is this easy or fun?

Abstraction

Let us reconsider the quote above:

“Software developers use abstraction to decompose complex systems into smaller components.”

This is absolutely true, and this has nothing to do with OOP.

This part is specific to OOP:

“An abstraction denotes the essential characteristics of an object that distinguish it from all other kinds of object and thus provide crisply defined conceptual boundaries, relative to the perspective of the viewer.”

This definition of “abstraction” leads to the advice of “program to an interface, not to an implementation”. Let us consider Chad Myers reflections on this advice, as he gleaned it from the book “Design Patterns: Elements of Reusable Object-Oriented Software”:

In the book, the author says: [Manipulating objects solely in terms of their interface and not their implementation] so greatly reduces implementation dependencies between subsystems that it leads to the following principle of reusable object-oriented design: Program to an interface, not an implementation. Don’t declare variables to be instances of particular concrete classes. Instead, commit only to an interface defined by an abstract class. This point is profound and if it isn’t already something you religiously practice, I suggest you do some more research on this topic. Coupling between types directly is the hardest, most pernicious form of coupling you can have and thus will cause considerable pain later. Consider this code example: public string GetLastUsername()

{

return new UserReportingService().GetLastUser().Name;

} As you can see, our class is directly new()’ing up a UserReportingService. If UserReportingService changes, even slightly, so must our class. Changes become more difficult now and have wider-sweeping ramifications. We have now just made our design more brittle and therefore, costly to change. Our future selves will regret this decision. Put plainly, the “new” keyword (when used against non-framework/core-library types) is potentially one of the most dangerous and costly keywords in the entire language — almost as bad as “goto” (or “on error resume next” for the VB/VBScript veterans out there). What, then, can a good developer do to avoid this? Extract an interface from UserReportingService (-> IUserReportingService) and couple to that. But we still have the problem that if my class can’t reference UserReportingService directly, where will the reference to IUserReportingService come from? Who will create it? And once its created, how will my object receive it? This last question is the basis for the Dependency Inversion principle. Typically, dependencies are injected through your class’ constructor or via setter methods (or properties in C#).

So, we want to GetLastUsername(). Before we introduce the complexity of OOP, lets go back to basics for a minute and think about the easiest way to get a last name, and then we will think about why the simplest way of doing this does not work for us.

We want to get a user’s last name. If we keep all data about a user in a hashmap, then we might have a key called “last_name” and we can call that key and get the last name. That is very basic and simple. What is wrong with this approach?

Well, the simplest approach doesn’t (always) work, because we probably have a contract that we want to enforce where the User is concerned. So let’s think about contracts, and compare contracts in OOP and non-OOP languages.

I think we can all agree that contracts are important, and we want our contracts enforced. “Design by contract” is an excellent methodology for developing software. I am sure we have all written software that had the concept of a User. We want a contract for User, which perhaps enforces these rules:

“first name” must be a string

“last name” must be a string

“date of birth” must be between 1890 and 2014

Up above there was an example of Pascal code that offered this struct:

TYPE chair = RECORD

model : integer;

weight : integer;

height : integer;

color : COLOR;

END;

Most programming languages that I am aware of offer something like a struct or a record or an enum or a class — we can use these to enforce contracts. However, whatever data structure we use, do we need the complexity that is apparent in Chad Myers example? A simple record can give us contract-enforcement, but a class comes with a whole extra set of baggage that programmers would be wise to avoid. Please ask yourself what is really needed here. Do we need a Service object to fetch the User for us? Do we need Dependency Inversion to set our current object with a Service object so we can fetch a last name? Do we need OOP?

At most, we need 2 things for our User:

1.) contract enforcement

2.) data hiding

We do not need OOP for this, and if we do use OOP then it inflicts on us a very high cost in terms of ceremony, setup, and complexity. How bad is that cost? Myers continues:

It’s also the case that the act of creating (new()’ing) an object is actually a responsibility in and of itself. A responsibility that your object, which is focused on getting the username of the last user who accessed the system, should not be doing. This concept is known as the Single Responsibility Principle. It’s a subtle distinction, and we usually don’t think of the “new” keyword as a responsibility until you consider the ramifications of that simple keyword. What if UserReportingService itself has dependencies that need to be satisfied? Your class would have to satisfy them. What if there are special conditions that need to be met in order for UserReportingService to be instantiated properly (existing connection to the database/open transaction, access to the file system, etc). The direct use of UserReportingService could substantially impact the functioning of your class and therefore must be carefully used and designed. To restate, in order to use another class like UserReportingService, your class must be fully responsible and aware of the impacts of using that class.

Please note the irony that Myers is arguing in favor of OOP, though his words can very easily be read as a criticism of OOP. He continues:

The Creational patterns are concerned with removing that responsibility and concern from your class and moving it to another class or system that is designed for and prepared to handle the complex dependencies and requirements of the classes in your system. This notion is very good and has served us well over the last 15 years. However, the Abstract Factory and Builder pattern implementations, to name two, became increasingly complicated and convoluted. Many started reaching the conclusion that, in a well-designed and interface-based object architecture, dealing with the creation and dependency chain management of all these types/classes/objects (for there will be many more in an interface-based architecture and that is OK), a tool was needed. People experimented with generating code for their factories and such, but that turned out not to be flexible enough.

In other words, the costs of this approach were so awful that even the proponents of OOP nowadays shrink away in horror. OOP was once seen as the silver bullet that was going to save the software industry. Nowadays we need a silver bullet to save us from OOP, and so, we are told (in the next paragraph), the Inversion of Control Container was invented. This is the new silver bullet that will save the old silver bullet.

The next 4 paragraphs are simply amazing, and not in a good way:

To combat the increasing complexity and burden of managing factories, builders, etc, the Inversion of Control Container was invented. It is, in a sense, an intelligent and flexible amalgamation of all the creational patterns. It is an Abstract Factory, a Builder, has Factory Methods, can manage Singleton instances, and provides Prototype capabilities. It turns out that even in small systems, you need all of these patterns in some measure or another. As people turned more and more of their designs over to interface-dependencies, dependency inversion and injection, and inversion of control, they rediscovered a new power that was there all along, but not as easy to pull off: composition. By centralizing and managing your dependency graph as a first class part of your system, you can more easily implement all the other patterns such as Chain of Responsibility, Decorator, etc. In fact, you could implement many of these patterns with little to no code. Objects that had inverted their control over their dependencies could now benefit from that dependency graph being managed and composited via an external entity: the IoC container. As the use of IoC Containers (also just known as ‘containers’) grew wider and deeper, new patterns of use emerged and a new world of flexibility in architecture and design was opened up. Composition which, before containers, was reserved for special occasions could now be used more often and to fuller effect. Indeed, in some circumstances, the container could implement the pattern for you! Why is this important? Because composition is important. Composition is preferable to inheritance and should be your first route of reuse, NOT inheritance. I repeat, NOT inheritance. Many, certainly in the .NET space, will go straight for inheritance. This eventually leads to a dark place of many template methods (abstract/virtual methods on the base class) and large hierarchies of base classes (only made worse in a language that allows for multiple inheritance).

Remember, we really only need, at most, 2 things for our User struct/record:

1.) contract enforcement

2.) data hiding (maybe)

We also very badly want one other thing:

3.) hierarchies of data-types

Proponents of OOP, such as Chad Myers, to get #1 and #2 are willing to sacrifice #3, even though #3 is very important, and even after that sacrifice, achieving #1 and #2 involves a mind-numbing degree of complexity. I am astounded that intelligent people actually defend these practices.

Please note that in the above paragraphs “dependencies” has a meaning that is specific to OOP. We are not talking about merely including libraries that your code will call — any good package manager will take care of that for you, and in 2014 we are blessed with a great abundance of good package managers. But Chad Myers is talking about “dependencies” in the sense of providing objects to an object at the time of instantiation — a problem that is inflicted on us by OOP. This kind of “dependencies” is not forced on us by computers, or programming, or logic, or whatever problem we are trying to solve, it is a problem that only exists in the world of OOP.

When I get into a discussion of this issue with proponents of OOP, I am often misunderstood as wanting a compromise between inheritance and composition, or arguing for multiple inheritance, at which point someone will tell me that mixins are the answer. But that misses the point: I want to have inheritance among my data-types, because data-types tend to have natural hierarchies that I want to model in my code, but I don’t want my data-types to be bound to specific behavior — I want something more flexible than that. But, even though the point is irrelevant to my argument, I will point out that, as Michele Simionato says, mixins come with their own set of problems, including namespace pollution:

Have a look at the hierarchy of the Plone Site class. Between square backets you can see the number of methods/attributes defined per class, except special attributes. The plot comes from a real Plone application I have in production. The total count is of 38 classes, 88 names overridden, 42 special names and 648 regular names: a monster. To trace the origin of the methods and to keep in mind the hierarchy is practically impossible. Moreover, both autocompletion and the builtin help facility become unusable, and the self-generated class documentation becomes unreadable since it is too big. …My hate for mixins comes from my experience with Zope/Plone. However the same abuses could be equally be done in other languages and object systems – with the notable exception of CLOS, where methods are defined outside of classes and therefore the problem of class namespace pollution does not exist – in the presence of huge frameworks. A consequence of namespace pollution is that it is very easy to have name clashes. Since there are hundreds of methods and it is impossible to know all of them, and since method overriding is silent, this is a real problem: the very first time I subclassed a Plone class I ran into this issue: I overrode a pre-defined method inadvertently, causing hard-to-investigate problems in an unrelated part of the code.

I would emphasize this:

“with the notable exception of CLOS, where methods are defined outside of classes and therefore the problem of class namespace pollution does not exist”

This is exactly what we want: to define our data-type hierarchy “outside of classes”, which is to say, independent of any functions. CLOS is the Common Lisp Object System and, as with Clojure (another Lisp) and Shen (another Lisp) and Haskell, the data-type definitions are independent of any behavior. This makes them more flexible, and this facilitates code re-use. Joe Armstrong (the inventor of Erlang) says this beautifully:

Objects bind functions and data structures together in indivisible units. I think this is a fundamental error since functions and data structures belong in totally different worlds. Why is this? *Functions do things. They have inputs and outputs. The inputs and outputs are data structures, which get changed by the functions. In most languages functions are built from sequences of imperatives: “Do this and then that …” to understand functions you have to understand the order in which things get done (In lazy functional programming languages (FPLs) and logical languages this restriction is relaxed). Data structures just are. They don’t do anything. They are intrinsically declarative. “Understanding” a data structure is a lot easier than “understanding” a function. Functions are understood as black boxes that transform inputs to outputs. If I understand the input and the output then I have understood the function. This does not mean to say that I could have written the function. Functions are usually “understood” by observing that they are the things in a computational system whose job is to transfer data structure of type T1 into data structure of type T2. Since functions and data structures are completely different types of animal it is fundamentally incorrect to lock them up in the same cage.

Code Re-use

Chad Myers has some quotes from the book “Design Patterns: Elements of Reusable Object-Oriented Software” which are relevant here:

[Inheritance] can cause problems when you’re trying to reuse a subclass. Should any aspect of the inherited implementation not be appropriate for new problem domains, the parent class must be rewritten or replaced by something more appropriate. This dependency limits flexibility and ultimately reusability. …Ideally you shouldn’t have to create new components to achieve reuse. You should be able to get all the functionality you need just by assembling existing components through object composition (via the container — Chad). But this is rarely the case, because the set of available components is never quite rich enough in practice. Reuse by inheritance makes it easier to make new components that can be composed with old ones. Inheritance and object composition thus work together. Nevertheless, our experience is that designers overuse inheritance as a reuse technique and designs are often made more reusable (and simpler) by depending more on object composition. You’ll see object composition applied again and again in the design patterns.

Again, OOP actively undermines the very thing it is suppose to promote: code re-use.

There are some OOP languages that are famous for enabling a high level of code re-use, and, among these, Ruby stands out as exceptional. But it is worth noting, the things that facilitate code re-use in Ruby are exactly those ideas that were drawn from non-OOP languages. OOP does not help with code re-use in Ruby. Yukihiro Matsumoto, who invented Ruby, credits Lisp with inspiring those parts of Ruby which help with code re-use, including the meta-programming and features such as “closures”:

Bill Venners: What makes a block a closure? Yukihiro Matsumoto: A closure object has code to run, the executable, and state around the code, the scope. So you capture the environment, namely the local variables, in the closure. As a result, you can refer to the local variables inside a closure. Even after the function has returned, and its local scope has been destroyed, the local variables remain in existence as part of the closure object. When no one refers to the closure anymore, it’s garbage collected, and the local variables go away. …Bill Venners: OK, but what is the benefit of having the context? The distinction that makes Ruby’s closure a real closure is that it captures the context, the local variables and so on. What benefit do I get from having the context in addition to the code that I don’t get by just being able to pass a chunk of code around as an object? Yukihiro Matsumoto: Actually, to tell the truth, the first reason is to respect the history of Lisp. Lisp provided real closures, and I wanted to follow that. Bill Venners: One difference I can see is that data is actually shared between the closure objects and the method. I imagine I could always pass any needed context data into a regular, non-closure, block as parameters, but then the block would just have a copy of the context, not the real thing. It’s not sharing the context. Sharing is what’s going on in a closure that’s different from a plain old function object. Yukihiro Matsumoto: Yes, and that sharing allows you to do some interesting code demos, but I think it’s not that useful in the daily lives of programmers. It doesn’t matter that much. The plain copy, like it’s done in Java’s inner classes for example, works in most cases. But in Ruby closures, I wanted to respect the Lisp culture.

(An aside: some people argue “Ruby proves that it is possible to have a low-ceremony OOP language.” Nowadays most languages have drawn inspiration from multiple sources, and many languages are multi-paradigm, so when I attack an OOP language, I am attacking those parts of the language that draw ideas from the OOP tradition. As Paul Graham has pointed out, over the years, nearly all languages have borrowed more and more features from Lisp. My point is, the features that allow Ruby to be low-ceremony are drawn from non-OOP languages.)

Ruby also allows code re-use through other means, such as Gems, and the Gems are able to plug into Ruby frameworks in part due to Ruby’s meta-programming features. Ruby allows a very high level of meta-programming, almost on par with the Lisps, but this comes at a cost: Ruby’s meta-programming features make it difficult to enforce type constraints or visibility guarantees. For instance, a method might be marked as “private” and yet you can still access it, thanks to meta-programming. In other words, to get all of the advantages of Ruby, you have to undermine its OOP features.

I admire Ruby very much: I think it is a beautiful language. It’s meta-programming makes it easy to compose functionality, thus allowing high levels of code re-use. Ruby is very slow, and monkeypatching can introduce bugs that are hard to trace, but, as Douglas Crockford said of Javascript, this is a Lisp with C syntax. But that raises the question, why don’t we just use Lisp? Apparently some people prefer C syntax, and feel that a Lisp with C syntax is something worth fighting for. Eric Kidd’s blog post “Why Ruby is an acceptable LISP” set off an intense debate, with dozens of people arguing that the world is a better place having Lisp features with a C syntax. What I find interesting is that you can see a debate in the comments, with dozens of intelligent people making hundreds of insightful remarks, and not one of the strengths mentioned go back to the OOP nature of Ruby. One of the strongest arguments made for Ruby was by “Eleanor”:

So to summarize: Ruby is a powerful language with a syntax that is easy even for non-programmers to get to grips with. It includes concepts to do with block closures, object-orientation and meta-programming which are usually absent from languages accessible to novice programmers and provides idioms for their usage which are easy to remember and use. There are without a doubt architectural techniques which can be utilized more easily in Lisp, but as to whether or not those are techniques which are actively useful for general software development is something that I think is open to debate.

I agree with this: Ruby is an easy way to learn most of the ideas that grew out of Lisp. But that implies that at some point, programmers hit a level of maturity where they should graduate from Ruby and move on to Lisp.

I also very much like this comment by “KristofU”:

I’m a C++ programmer, and was looking for a new language to learn and do stuff more elegantly. Ruby just sucked me right in. There is almost nothing to learn, it’s just there. You can slice and dice and juggle and the result is always a working program. You like for-statements? Well, you can use for-statements. You like iterators? Well, you can use iterators. Make object functors or lambda’s, whichever you prefer. Ruby doesn’t force anything upon you, there is time to learn to appreciate the finer features, while still churning out working apps in the meantime. I’ve also briefly tried Haskell, Scheme and Erlang, but I have to say, I couldn’t get anything done. Compared to Ruby, quite an anti-climax.

Ruby is dynamic, low-ceremony and does not need to be compiled, so you can skip past the complexity of the data-type checking that is mandatory in Haskell, and you (mostly) don’t have to worry about organizing your code for “supervisory trees” like you do in Erlang. Of course, Ruby is incapable of doing most of the stuff that you can do with Haskell or Erlang. Below I’ll quote from Joe Armstrong’s work on Erlang, where he points out that Ericsson builds telephone switches (with Erlang) that are expected to have only 2 hours of downtime per 40 years!!! You could never build anything that reliable with Ruby — what makes it easy also limits its reliability. All the same, I think Ruby has great strengths. But those strengths have nothing to do with OOP.

And having said all that, it has to be noted that Ruby has more ceremony than what it should have, especially considering its reputation. I’ll say more about that later, but also, Stuart Halloway mentions Ruby while he makes the point that code re-use, in any language, is killed off by the amount of ceremony that is necessary to get anything done:

Good code is the opposite of legacy code: it captures and communicates essence, while omitting ceremony (irrelevant detail). Capturing and communicating essence is hard; most of the code I have ever read fails to do this at even a basic level. But some code does a pretty good job with essence. Surprisingly, this decent code still is not very reusable. It can be reused, but only in painfully narrow contexts, and certainly not across a platform switch. The reason for this is ceremony: code that is unrelated to the task at hand. This code is immediate deadweight, and often vastly outweighs the code that is actually getting work done. Many forms of ceremony come from unnecessary special cases or limitations at the language level, e.g. factory patterns (Java) dependency injection (Java) getters and setters (Java) annotations (Java) verbose exception handling (Java) special syntax for class variables (Ruby) special syntax for instance variables (Ruby) special syntax for the first block argument (Ruby) High-ceremony code damns you twice: it is harder to maintain, and it needs more maintenance. When you are writing high-ceremony code, you are forced to commit to implementation approaches too early in the process, e.g. “Should I call new, go through a factory, or use dependency injection here?” Since you committed early, you are likely to be wrong and have to change your approach later. This is harder than it needs to be, since your code is bloated, and on it goes.

What we want, at all times, is the least amount of ceremony that still allows us to get our job done. Getting our job done tends to mostly involve data transformations (some would prefer to say “managing state safely”) and enforcing data-type contracts. Depending on your programming goals (reliability? speed of development?) there are functional programming languages that deliver what we want much better than OOP. I’ll offer some insights from the world of Clojure, as I know it better than any other functional language.

Clojure promotes code re-use through flexible functions that can work on many data-types:

Many types, one interface One of Clojure’s core features is its generic data-manipulation API. A small set of functions can be used on all of Clojure’s built-in types. For example, the conj function (short for conjoin) adds an element to any collection, as shown in the following REPL session: user> (conj [1 2 3] 4)

[1 2 3 4] user> (conj (list 1 2 3) 4)

(4 1 2 3) user> (conj {:a 1, :b 2} [:c 3])

{:c 3, :a 1, :b 2} user> (conj #{1 2 3} 4)

#{1 2 3 4} Each data structure behaves slightly differently in response to the conj function (lists grow at the front, vectors grow at the end, and so on), but they all support the same API. This is a textbook example of polymorphism — many types accessed through one uniform interface. Polymorphism is a powerful feature and one of the foundations of modern programming languages. The Java language supports a particular kind of polymorphism called subtype polymorphism, which means that an instance of a type (class) can be accessed as if it were an instance of another type. In practical terms, this means that you can work with objects through a generic interface such as java.util.List without knowing or caring if an object is an ArrayList, LinkedList, Stack, Vector, or something else. The java.util.List interface defines a contract that any class claiming to implement java.util.List must fulfill.

“Many types, one interface” promotes code re-use, whereas the cornucopia of interfaces in OOP languages undermines code re-use. As Rich Hickey (inventor of Clojure) has said “All that specificity [of interfaces/classes/types] kills your reuse!”

Of course, if you are very careful, you can achieve fairly high levels of code re-use in any language, including any OOP language. But there tends to be trade-offs involved: achieving one goal means sacrificing another. To achieve high levels of re-use in OOP languages, one is often forced to write very small classes, which leads to an explosion in the number of classes in your system. John Barker makes this point:

The typical college introduction to OOP starts with a gentle introduction to objects as metaphors for real world concepts. Very few real world OOP programs even consist entirely of nouns, they’re filled with verbs masquerading as nouns: strategies, factories and commands. Software as a mechanism for directing a computer to do work is primarily concerned with verbs. OOP programs that exhibit low coupling, cohesion and good reusability sometimes feel like nebulous constellations, with hundreds of tiny objects all interacting with each other. Sacrificing readability for changeability. Many of OOP best practices are in fact encouraged by functional programming languages.

Joe Armstrong (the inventor of Erlang) indirectly makes the point that plain data structures are more reusable than objects:

Consider “time”. In an OO language “time” has to be an object. But in a non OO language a “time” is an instance of a data type. For example, in Erlang there are lots of different varieties of time, these can be clearly and unambiguously specified using type declarations, as follows: -deftype day() = 1..31.

-deftype month() = 1..12.

-deftype year() = int().

-deftype hour() = 1..24.

-deftype minute() = 1..60.

-deftype second() = 1..60.

-deftype abstime() = {abstime, year(), month(), day(), hour(), min(), sec()}.

-deftype hms() = {hms, hour(), min(), sec()}. Note that these definitions do not belong to any particular object. They are ubiquitous and data structures representing times can be manipulated by any function in the system. There are no associated methods.

Design Benefits

I’ll repeat the quote above:

“Object Oriented Programs force designers to go through an extensive planning phase, which makes for better designs with less flaws.”

This is a surprising appeal to the hated Waterfall development method:

The waterfall model is a sequential design process, used in software development processes, in which progress is seen as flowing steadily downwards (like a waterfall) through the phases of Conception, Initiation, Analysis, Design, Construction, Testing, Production/Implementation and Maintenance. The waterfall development model originates in the manufacturing and construction industries; highly structured physical environments in which after-the-fact changes are prohibitively costly, if not impossible. Since no formal software development methodologies existed at the time, this hardware-oriented model was simply adapted for software development.

The waterfall method is risky because you only gain benefits from your software at the end of a long process — you might have to wait months, or even years, before the users of your software get to use it, and only then can they give you feedback about whether it actually helps them. To reduce risk, many organizations have moved to lean and agile methods of development:

Agile is adaptive, not predictive.

Do you remember what “waterfall” was like back in the day? We spent months gathering business requirements, writing specs, and designing, and then spent the next 10 months coding. Since we spent the first few months trying to predict what the next 10 months would entail, we could never accurately estimate how much work a task was supposed to be, and heaven forbid the requirement changed half way through! Agile is an attempt to shorten that cycle so we don’t have to waste 10 months before find out something was wrong.

The waterfall method would be worth it if it lead to better software, but the opposite is true: because the development receives no feedback till the end of the process, the software produced by this method tends to be worse. Agile Builds Trust with Fast Feedback

Agile development addresses this problem by iterative delivery of system functionality to meet requirements that people know they need today. Because people aren’t asked to think of everything they could ever want, the number of requirements is much more manageable. And even within existing requirements, some requirements are always more important than others so if IT can deliver on those requirements right away (in 30 day cycles for instance), then business people get more value more quickly and the process builds mutual trust based on fast feedback and shared success.

More so, the idea that fast iterations lead to better outcomes is grounded on solid research, going all the way back to John Boyd who came up with the OODA loop:

According to Boyd, decision-making occurs in a recurring cycle of observe-orient-decide-act. An entity (whether an individual or an organization) that can process this cycle quickly, observing and reacting to unfolding events more rapidly than an opponent, can thereby “get inside” the opponent’s decision cycle and gain the advantage. …The same cycle operates over a longer timescale in a competitive business landscape, and the same logic applies. Decision makers gather information (observe), form hypotheses about customer activity and the intentions of competitors (orient), make decisions, and act on them. The cycle is repeated continuously. The aggressive and conscious application of the process gives a business advantage over a competitor who is merely reacting to conditions as they occur, or has poor awareness of the situation… The approach favors agility over raw power in dealing with human opponents in any endeavor.

About this:

“In addition, once a program reaches a certain size, Object Oriented Programs are actually easier to program than non-Object Oriented ones.”

Basic math tells us this is untrue: since OOP depends on a graph of objects that mutate each other’s state, the number of possible mutations increases exponentially with the number of objects, minus whatever limits can be imposed through contract enforcement and data hiding. But state is everywhere in an OOP program, so it takes extreme efforts to keep the number of possible mutations to a manageable level in a large program. When state is independent of classes, it becomes easier to centralize all the state in an app, and thus it becomes easier to protect it, but when state is inside of classes, as it must be with OOP, then it is difficult to protect, in part because it is spread out everywhere. Ask a Java programmer how many non-constant (mutable) variables exist in their current project and they would have to do some careful research to find out the answer. As a point of contrast, a typical Clojure app centralizes all state in a few global vars, which are then worked upon by all the functions in the program — the idea of “few nouns, lots of verbs” works to keep the state at a manageable amount. In large Clojure apps, like any software, the amount of state can eventually reach a scale where changes become complicated, but even then it is helped by the fact that the state is separate from the behavior.

As to large scale applications, it is worth noting that one of the Ericsson phone switches that Joe Armstrong worked on contains 1.7 million lines of Erlang code, and has a very high reliability requirement: no more than 2 hours of downtime every 40 years. This would be difficult or impossible using an OOP language.

Software Maintenance

About this:

“An Object Oriented Program is much easier to modify and maintain than a non-Object Oriented Program. So although a lot of work is spent before the program is written, less work is needed to maintain it over time.”

I won’t waste much time pointing out how wrong this is. The ability to maintain code over the long term depends crucially on the ability of programmers to understand the code, and no programmer can correctly reason about a graph of mutating state once that graph grows large enough — too many interactions begin to occur.

Also, OOP tends to be bloated, containing a lot of useless boilerplate code, so for the exact same amount of functionality, software written in a different style would be smaller and easier to think about.

Single responsibility principle

Uncle Bob argues for SRP in this way:

The Single Responsibility Principle (SRP) says that a class should have one, and only one, reason to change. To say this a different way, the methods of a class should change for the same reasons, they should not be affected by different forces that change at different rates. As an example, imagine the following class in Java: class Employee {

public Money calculatePay() {…}

public void save() {…}

public String reportHours() {…}

} This class violates the SRP because it has three reasons to change. The first is the business rules having to do with calculating pay. The second is the database schema. The third is the format of the string that reports hours. We don’t want a single class to be impacted by these three completely different forces. We don’t want to modify the Employee class every time the accounts decide to change the format of the hourly report, or every time the DBAs make a change to the database schema, as well as every time the managers change the payroll calculation. Rather, we want to separate these functions out into different classes so that they can change independently of each other. Of course this seems to fly in the face of OO concepts since a good object should contain all the methods that manipulate it. However, decoupling tends to trump ideals like this. We don’t want business rules coupled to report formats, and so we need to put these functions in different classes.

This is another case of a problem that only exists because of the ceremonies forced on us by OOP. Perhaps we should have global vars that are atoms, one for pay and one for hours, or perhaps we’d like to keep this in a hashmap inside of a ref (the ref giving us transactional guarantees so we don’t have to worry about stuff like locks and synchronization) then we might have 100 functions, or 200 functions, that modify these vars, but at no point would we have a class about which we would have to ask “Am I obeying the Single Responsibility Principle?”

Open/closed principle

Up above I quoted John Barker:

“OOP programs that exhibit low coupling, cohesion and good reusability sometimes feel like nebulous constellations, with hundreds of tiny objects all interacting with each other.”

This tendency toward having too many classes is exemplified in examples of the Open/closed principle:

A simple example of the Open/Closed Principle

Now our customer, Aldford, wants us to build an application that can calculate the total area of a collection of rectangles. That’s not a problem for us. We learned in school that the area of a rectangle is it’s width multiplied with it’s height and we mastered the for-each-loop a long time ago. public class AreaCalculator

{

public double Area(Rectangle[] shapes)

{

double area = 0;

foreach (var shape in shapes)

{

area += shape.Width*shape.Height;

} return area;

}

} We present our solution, the AreaCalculator class to Aldford and he signs us his praise. But he also wonders if we couldn’t extend it so that it could calculate the area of not only rectangles but of circles as well. That complicates things a bit but after some pondering we come up with a solution where we change our Area method to accept a collection of objects instead of the more specific Rectangle type. Then we check what type each object is of and finally cast it to it’s type and calculate it’s area using the correct algorithm for the type. public double Area(object[] shapes)

{

double area = 0;

foreach (var shape in shapes)

{

if (shape is Rectangle)

{

Rectangle rectangle = (Rectangle) shape;

area += rectangle.Width*rectangle.Height;

}

else

{

Circle circle = (Circle)shape;

area += circle.Radius * circle.Radius * Math.PI;

}

} return area;

} The solution works and Aldford is happy. Only, a week later he calls us and asks: “extending the AreaCalculator class to also calculate the area of triangles isn’t very hard, is it?”. Of course in this very basic scenario it isn’t but it does require us to modify the code. That is, AreaCalculator isn’t closed for modification as we need to change it in order to extend it. Or in other words: it isn’t open for extension. In a real world scenario where the code base is ten, a hundred or a thousand times larger and modifying the class means redeploying it’s assembly/package to five different servers that can be a pretty big problem. Oh, and in the real world Aldford would have changed the requirements five more times since you read the last sentence :-) One way of solving this puzzle would be to create a base class for both rectangles and circles as well as an