The features of object orientation
Which features of object-oriented programming are genuinely useful in a wide variety of situations; which are only occasionally useful; and which are either irrelevant or hindrances. This is an incomplete list, which I will probably add to in the future as more thoughts on this subject come to me.
Widely useful
Brevity. This is often overlooked, but brevity is more important than people think. With object orientation, one can say "
list.append(value)
" instead of "list_append(list, value)
".Naïvely, one would think this is due to namespacing, another common feature of OO languages: the method "append" is namespaced within the "List" interface/class, so you don't have to disambiguate when you use "append" on an instance of "List". However, in dynamically typed languages, there need not be any interface or class "List" specifying an "append" message. More revealingly, consider a multi-dispatch system like CLOS where methods ("generic functions") are not namespaced within classes - they're invoked using prefix syntax like everything else.
The real reason why object orientation gives brevity is because one name can stand for multiple implementations - the "append" method is dynamically bound to an anonymous implementing function at runtime based on the receiving object's type. Namespacing is an entirely orthogonal feature.
In a language without dynamic binding like C, you have to manually disambiguate between implementations; the usual convention is to give them a prefix based upon the type of what, in an OO language, would be the receiving object. Think of all the "
str
"-prefixed functions in<string.h>
.Polymorphism. The polymorphism on object implementation that OO provides leads directly to modularity: differing back-ends can be hooked up to the same front-end; the same logic can drive different underlying mechanisms. I don't think I need to discuss at length why modularity is a good thing, but to give a few brief examples of its advantages: less code needs to be written (particularly of the boilerplate/glue kind), programs become easier to reason about and test, and inter-unit dependencies (and hence compilation times) are decreased.
Occasionally useful
Applicability to the problem domain. Object-orientation happens to be a very good model for certain kinds of problems. For example, stealing from Paul Graham, simulations and CAD systems. However, as this isn't very much of an advantage unless you happen to be working on such a project, this is hardly a reason to design a general-purpose language around the idea of object-orientation.
Inheritance. Inheritance is a very restricted form of code reuse. Code reuse is of course a good thing, and strongly related to modularity. But if inheritance is the only form of code reuse provided (besides plain old functions), one often ends up in situations where this is an unwanted restriction.
Closures, for example, can be imitated using objects and methods; but this is clunky, especially in a strongly-typed language where you'd really like to be able to use a type expression for the function you're using rather than defining an interface to represent it. Much the same argument applies to coroutines and iterators.
Adapters are a somewhat less potent example, illustrating merely the problems in the most common implementations of inheritance and classes rather than OO in general. Adapters, in OO terms, are usually defined as classes that use an object of one interface (the source) to implement a different interface (the target). But if (as is often the case) an adapter requires no functionality beyond that of the source, it would be nicer to just define the methods of the target directly in terms of the source, so that any instance of the source can be treated as an instance of the target.
The only real way to do this in an OO language without some other form of code reuse, like Ruby's mixins, is to add methods to a base class from which all objects implementing the source interface are descended. In single-inheritance languages, this is problematic because often there is no such base class; and in many languages, adding methods to existing classes simply isn't supported. The only multi-inheritance languages which support adding methods to classes I know of are: Python, where adding methods this way is unusual but possible; and CLOS, where this is in fact the standard way to define methods and this pattern is completely supported. Kudos to CLOS for getting this right.
Hindrances and irrelevancies
Strong static typing. Object-orientation does not imply or even facilitate a static type system. There's a reason why the pioneering OO languages were mostly dynamically typed; and there's also a reason why most very strongly typed languages aren't OO (the main exception I know of being OCaml). Dynamic typing suits OO because it easily accommodates ad hoc polymorphism and dynamic binding; and because it has synergy with the rapid-prototyping and agile methodologies which OO lends itself to.
Information hiding. Information hiding, often called or subsumed by the term "encapsulation", makes the language do a job better accomplished by simple self-discipline: it prevents something that is usually, but not always, a bad idea. Note that by "information hiding" here I mean specifically the explicit access restrictions that can be placed on instance variables, methods, etc. I'm not talking about implicit information-hiding due to polymorphism and modularity in general.
The benefits information hiding gives you are few and weak. You don't get high-level semantic assurances like those that a strong and expressive type system gives you. You merely get an assurance that certain classes won't directly access certain parts of other classes. But unless your basic assumption is that programmers are idiots who don't read documentation, anyone trying to access that part probably knows why they want to do so and what its effects will be. In particular, naming conventions can clearly indicate that a certain function isn't to be accessed arbitrarily without unnecessarily restricting a programmer who knows what s/he's doing.