Hacker News new | ask | show | jobs
by chton 4291 days ago
What this article seems to miss is part of the raison d'ĂȘtre of Object Oriented Programming. It's not just about how you encapsulate state and how you act on that state. Forget the exact way the type system works, or what extension methods are, or even what polymorphism is.

The big advantage of OO is that it acts as a distillation of how humans think. We're accustomed to thinking in terms of 'things that do stuff'. What OO provides is essentially a skeuomorphic element to your code, where your basic units have some resemblance to real items and concepts. This makes it a lot easier to reason about large codebases, and makes them easier to document (in theory). It means the most important thing you need to understand how a piece of business logic works is knowledge of the business. You don't need to know anything about the data, or how the application is composed in order to comply with the needed use case. If you know the concepts and their behaviour in the problem domain, you will be able to make sense of how the code is written.

FP has its place, as does procedural code, but advocating either of them as a complete replacement for OO is short-sighted. Claiming FP is a solution to OO's shortcomings is too. Each has its place. If anything, we should be working towards next-generation models, that combine the advantages of both and mitigate the downsides of both.

11 comments

> The big advantage of OO is that it acts as a distillation of how humans think.

Honestly, while I think OO programming in the broadest sense does that, I think class-oriented OOP (what the article mostly focusses on) languages, particularly statically-typed class-oriented languages in the C++/Java lineage--don't do a great job of either supporting that intuition or facilitating applying it intuition to the construction of correct, maintainable computer programs. They aren't useless in that respect--there is a reason why they flourished--but there's also a reason that after them an important programming paradigm for several decades, and a dominant one since at least the late 1980s, there's a whole lot of moves away from traditional class-oriented OOP in newer languages.

I think that we're seeing a model--which is mostly viewed as being within the FP tradition but which has learned a lot from OOP languages and supports a lot of OO thinking--emerge (and that this article points to a lot of its elements) that provides a framework that better matches the intuition than class-oriented OOP does, while also better supporting building correct, maintainable, easy-to-reason-about systems.

>don't do a great job of either supporting that intuition or facilitating applying it intuition to the construction of correct, maintainable computer programs

My first thought is that this is dependent on implementation. It is possible to write classes in a way that aligns with intuition, but it is sometimes hard to do that, and even if you're great at OOP it is hard to do consistently. I think the Smalltalk message-sending way of thinking has huge value because it is easy to reason with, and facilitates this intuition.

That said, I do see tremendous value in FP, and I'm encouraged by the elements of FP that I've seen popping up in Swift. So I guess ultimately I do agree with you. I'd like to see OOP continue to flourish, but borrow elements from the Functional style that make it very difficult to write fragile code.

I'm exactly in your camp. I would love to see more functional influence in OO, and more careful thought about what to use at what time.
> The big advantage of OO is that it acts as a distillation of how humans think.

Citation needed.

Browsing around Google Scholar for variations of "object oriented empirical comparison" shows a huge body of research comparing various OO approaches to each other, but very few comparing OO approaches to anything else. Those which I have been able to find compare OO to procedural code, and find either no significant difference in comprehension levels, or that procedural code is easier to understand (ie. closer to "how humans think") than OO:

An empirical study of novice program comprehension in the imperative and object-oriented styles

http://ftp.cs.duke.edu/courses/fall00/cps189s/readings/p124-...

Assessing the cognitive consequences of the object-oriented approach: A survey of empirical research on object-oriented design by individuals and teams

http://arxiv.org/pdf/cs.HC/0611154

An exploratory study of program comprehension strategies of procedural and object-oriented programmers

http://www.ptidej.net/courses/inf6306/fall11/slides/11%20-%2...

I've only been able to find one source comparing OO with functional programming, which didn't measure comprehension. Instead, it compared code quality metrics between C++ and Standard ML. Most showed no significant difference, except for SML taking longer to run its tests (it also had more tests), having higher code and library re-use and having a larger number of errors per 1000 lines (although the same number of known errors overall):

Comparing programming paradigms: an evaluation of functional and object-oriented programs

http://eprints.soton.ac.uk/250597/1/report3_Harrison_95.pdf

The most commonly cited proponents of this viewpoint are Rosson and Alpert (http://dl.acm.org/citation.cfm?id=1455754, behind a paywall). The first study you linked refers to them and a few other explicitly, and uses their research as a basis. It's difficult to find much more than those, because this kind of 'programming philosophy' is rarely under this level of academic scrutiny.

Aside from official sources, it's a statement that I didn't think needed much citation. It's absolutely fair to criticize it, but it's a widely-held belief that seems to hold true (at least anecdotally)

The reason I was initially skeptical of these kinds of claims is because:

(1) Many of those people making it weren't too experienced in reasonable alternatives.

(2) Many developers I know (also anecdotally) spent years studying OOP to get to the point where they can use most of its higher level patterns effectively, and judge FP based off a single class or toy project built in a some lisp derivative, or what they heard from a friend.

(3) Those people making the opposite claim actually had fair bit of experience with both methodologies, since it is hard to avoid OOP.

In other words, it seems like the claim "OOP fits the brain better" is a prevailing meme, largely among those who have not tested the claim effectively, while "FP is pretty good and we need to lean on it more" is fairly popular with those who have actually tested the claim, instead of relying on hearsay.

Obviously, my personal experience shouldn't convince you that your statement is wrong. (I was a big fan of OOP who devoted quite a bit of time learning software engineering with both classes and prototypes before trying out FP and finding out just how much OOP was silly and could be replaced with simpler, more composable FP ideas). Nor do I think that all of the claims made by the FP people are right. But realize that your statement DOES require significant evidence to back its claims, and that resorting to populism gives it relatively little real support.

> The big advantage of OO is that it acts as a distillation of how humans think.

I would consider this a disadvantage, not an advantage. Human thoughts are imprecise and carry rich but ambiguous connotations. The major advances of mathematics in the 19th century (or thereabouts) onward are closely tied to the divorce of notation and natural language.

The ancient version of the Pythagorean theorem is something like, "The area of a square whose side is the length of a hypoteneuse of a right triangle is equal to the sum of the areas of squares whose sides are equal in length to the other two sides." A modern version is more like, "Let a, b, c be the lengths of sides of a right triangle, where c is the length of the hypoteneuse. Then a^2 + b^2 = c^2." You can see as time goes on, the text becomes simultaneously clearer, more concise, and more abstract.

This is why natural language programming is doomed to failure. Others have expressed the point better than I do (notably Dijkstra). But you can look at the examples of how inheritance in class-based OOP systems work and you will get sick just looking at them: examples of Dog inheriting from Animal, and Penguin from Bird (but penguins don't fly), et cetera. The real disadvantage here is that once people start thinking about taxonomy in general (which class-based OOP encourages), you're not thinking about programming any more.

The difficulty people have with even simple problems like "how do you describe squares and rectangles in a computer program" is another good illustration of how the class-based object-oriented system of thinking is unsuited for solving computational tasks, at least compared to the alternatives.

The big advantage of OO is that it acts as a distillation of how humans think. We're accustomed to thinking in terms of 'things that do stuff'. What OO provides is essentially a skeuomorphic element to your code, where your basic units have some resemblance to real items and concepts. This makes it a lot easier to reason about large codebases, and makes them easier to document (in theory).

It seems to me that you're sort of confusing OOP with programming interfaces.

An interface describes a model of how to use a certain piece of code, and indeed a good one can be almost "obvious" and it begins to feel like a "natural" way to reason with it. But it's all about the interface: not about from what kind of language constructs the interface is composed of.

Interfaces can be done in object oriented programming too but for some reason, possibly exactly because of the resemblance to real items and concepts and how human people are so fond of those, most interfaces in OOP languages are utter horror.

This could be because it's so easy and almost fundamental to create "things that do stuff", i.e. classes in OOP, there will be a lot of them. The design pattern craze kind of formalized that for good, which is why we've all enjoyed our share of abstract factory builder singleton visitor, or whatever.

In contrast, you tend to see really good interfaces surprisingly often in... C.

As a disclaimer, this is a big reason why I like C language -- it forces you to think simple because it offers so many guns to shoot yourself in the foot and a lot of other places too that you need to focus on what's essential to your program. With an easier but inevitably more complex language, the lull times in the day of programming seem to produce lots of implementation and interfacing complexity that a C programmer would never dare to attempt. C programmers also use paradigms associated with OO but only where appropriate because it's a bit of hurdle to implement those in C.

I've also observed that there's a vague parallel between complex (object oriented) interfaces vs. simple (C) interfaces and the Alan Perlis' notion of to better have 100 functions operating on one data structure rather than 10 functions operating on 10 data structures. Good OO interfaces tend to be really simple and short, even so that they're not even particularly OO anymore.

The OO, procedural, FP paradigms are mostly orthogonal and can be combined freely in sensible amounts where needed, but they're also orthogonal to concepts such as encapsulation, polymorphism, type hierarchies, and inheritance which themselves aren't tied together either.

My intention was focused entirely on object oriented modelling and programming. Interface design is a tool to do that, but in and of itself does not provide the correspondence with the way humans think. The core of OO is to have independent objects that combine behaviour and data. Whatever your type system, whatever your language constructs, that core is what provides the advantage. I was considering mostly the basic ideas of OO modelling in general rather than whatever way you choose to achieve that.
http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom...

Steve Yegge's "Execution in the Kingdom of Nouns" has some interesting commentary on the idea of OO being in any way how humans think. The allegory has some harsh things to say about Java, which are not my intention in suggesting this link. The observations that objects tend to be nouns while functions tend to be verbs is very interesting.

/* footnote 3 is hilarious */

"The big advantage of OO is that it acts as a distillation of how humans think."

I first encountered functional programming in the 1980s on my Computer Science degree course a few years before I encountered OOP (CLOS and then C++) and I'm not convinced that OOP is fundamentally closer to "how humans think" than FP. Most programmers these days were taught an OOP language first so think that is most natural - but I don't think there is anything fundamental about that.

You should try explaining some business logic to a non-technical person some time. If you are able to properly model the problem domain, non-technical people have a much easier time understanding the flow of the code and how it works if it's written in an OO way. This is precisely because they recognize the concepts and ideas they are familiar with and can already reason about. They know that 'a Person pays their Bills by asking a Bank to deposit Money'. This means they can make sense of code that is structured in the same way. FP, for all its advantages and elegance, doesn't offer that same correspondence.
> The big advantage of OO is that it acts as a distillation of how humans think.

Objects are always a struggle. I see students new to programming take as long as their junior year before they even start to "really get it" and design reasonable classes.

Rolling identity, state, values, types, functions, polymorphism, modules, resource management, and who knows what else into a single thing is inherently going to result in something pretty damn complicated, compared to trying to keep those concerns orthogonal and thus only pulling in those that are needed for the task at hand.

I would certainly say that OOP-based software engineering has vast advantages in certain cases, but my hypothesis would be that its "ease" advantages is more one of mindshare rather then something inherent in the human mind. This hypothesis, however, is worth extensively testing... for a discipline that relies on stretching human cognitive performance to its limits, we spend far too little time actually figuring out exactly what limits those are.

> skeuomorphic

No, skeuomorphism involves ornamental details, which are at best hints about how something is to be used.

How you break-down the responsibilities of your system and name them is much much more important than that.

I agree it's not the best word for it, but what I meant is that the elements are made to look and behave similar to their real-life or conceptual analogues. Think of it mostly as the software UI skeuomorphism: we are able to recognize the functions of the software faster because it is designed to look like something we know.
> The big advantage of OO is that it acts as a distillation of how humans think. We're accustomed to thinking in terms of 'things that do stuff'.

Let's not confuse "how humans think" with "how humans ought to think to self problems effectively". There is little evidence that OO is any better than other principled approaches to programming.

> The big advantage of OO is that it acts as a distillation of how humans think.

With how widespread OO is now and in the last decades, how much it is taught and how important it is in a fair share of popular programming languages (or even mandatory, for all practical purposes), this point might just be a self-fulfilling prophecy (if I'm using that expression correctly).

The way OOP is taught often doesn't bring up object thinking. But if you believe it is not natural, try thinking mathematically (without nouns or names as unique aliasable identifiers). Or without isa or hasa relationships. Our minds have 50,000+ years of language expertise, and only a couple thousand for formal non linguistic equational reasoning (where things only have structure and are unnameable).
I'm not so sure. There's some truth to what you're saying, but by "is a", statically typed OO languages generally mean something much different than what we mean by that in human languages. I find OO's obsession with hierarchy and taxonomy to be profoundly unintuitive.
There is much more to OOP than Java.
Something like Smalltalk or Ruby is certainly closer to my preferences. The focus on taxonomy is definitely most obvious and most painful in languages with static typing and fewer dynamic features.

Can you suggest an OO language that really avoids the issue, though? It seems inherent in the notion of inheritance to me, even interface-only inheritance. Something like Haskell's typeclasses or Rust's traits seems to me like an easier way to model concepts from the real world.

Believe it or not, Scala can be quite powerful since it supports mixin-like traits. I'm not sure about "avoiding" taxonomy though, I find variants useful, but I also like to play with layers (think modularized features of variants).

Type classes aren't reall OO, I mean, they allow for some non-nominal subtyping that meshes with purity. I would argue that OO is really about the names, and OO thinking is really just a way of naming everything in your problem, while type classes mostly keep with the name-free equations reasoning.

> The way OOP is taught often doesn't bring up object thinking. But if you believe it is not natural, try thinking mathematically (without nouns or names as unique aliasable identifiers). Or without isa or hasa relationships.

Is-a and Has-a relationships don't require class-based OO structures to express in a language. E.g., both membership in a abstract group sharing a common interface (is-a) and composition (has-a) relationships are readily expressed in FP languages like Haskell quite directly, or in languages that are more like traditional OO langauges but which separate interface from implementation rather than combining them as is done in class-based OO.

The OO approach to programming, and thinking about domains, has broad utility, but the particulars of static, class-based OOP are not necessary to realize that utility.

> but the particulars of static, class-based OOP are not necessary to realize that utility.

The design goal of a OOPL is to support object thinking. FPL generally have other goals, and some of their design philosophies reject object thinking altogether. You'll often see lots of objects in ML or Scheme libraries; but the languages are not really optimized for this way of solving problems.

Haskell, as a real pure FPL, is really the anti-thesis of object thinking. You cannot express nominal is-a relationships in Haskell very easily at all: it is all structural (and type classes don't get around that) and supports equational rather than name-based reasoning. You could add names to Haskell via GUIDs or impure language features. This is not really the way to program in Haskell, however.

> The design goal of a OOPL is to support object thinking.

Yes, my point is that class-based OOPLs aren't the only way to do that (and in some respects create some unnecessary problems with that), which is among the reasons that many newer languages -- even ones that are not particularly functional languages, and which have OO roots -- are not class-based.

A "class" is quite useful to programmers vs. some of the alternatives; even JavaScript is (syntactically at least) moving away from prototypes to having real class constructs. I prefer traits (the mixin-like scala kind, not the field-free smalltalk kind), which are basically classes enhanced with linearized multiple inheritance. There are also Beta-style virtual classes, which are quite useful, and there are even languages that support dynamic inheritance (via prototypes, predicates, or on demand).

The OOPL design space is huge. I wish there was more activity there, but all the new hot languages either do little to innovate on OO constructs, or emphasize the functional (or worse: try to push type classes as OO).

Then again... capturing things with hierarchical, permanent, non-context dependent hasa / isa relationships is very, very far removed from how we've used language for the past 50k years.
Can you give me an example? I'm at work right now in a hierarchical, permanent, non-context dependent environment and is-a, has-a relationships abound. We deal with the complexity of the world by organizing it into hierarchies.
Language is incredibly fuzzy... and for good reason.

Creating fixed structures that span across groups of people is incredibly hard. Just take a look at how much work/debate has gone into the taxonomy of life.

Apart from that relationships are context dependent. I can have a father but if he passes away I still have one in some sense but not in another.

I can also have ideas... or friends which can be mutual or not. Heck... even "I" isn't fixed. If I'm sleepwalking it's me but not really me.

My point was: do you know of any OOP language which can fluently handle this without having the object metaphor break down?

No language can encode exactly how we think. We aren't going to get there until we have hard machine intelligence (then we are programming anymore). But we definitely think with objects, and OOP languages are simply trying to exploit that (we can definitely debate about how well!).

OO thinking has no problem with stateful reasoning, your father can be currently dead and previously alive.

'skeumorphic' - did you mean 'anthropomorphic'?
I didn't. I meant 'skeuomorphic' as in 'designed with cues that correspond to reality, to indicate corresponding functions and behaviour'. It's a bit more nebulous when applied to real code, since we're thinking in terms of concept and behaviour, but the same thought applies.