Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I strongly reject the idea that object orientation hasn't provided a big boost to programmer productivity. In my view, it's enabled building systems that are orders of magnitude larger and more complex because of the discipline it enforces in modularity and the discoverability it lends to APIs.

I mean, do you remember the C written in the 80s? Often, the only unit of modularity in common use was the translation unit, with static globals used freely, structures with no visibility protection, having their inner guts manipulated by different modules, frequently by manually tweaking the pointers etc.? If you had an API that protected structural guts, you were almost always essentially programming to an object oriented style, only with no help from the language and compiler.



I think a lot of the benefits of OO reuse have been lost due to platform shifts. If you build a system on NeXTSTEP in the early 90s, then throw it out and switch to Java, then throw it out and switch to C#, you're naturally going to lose a lot of the efficiencies you theoretically could have taken advantage of had you somehow managed to stay on NeXTSTEP or OpenStep all along.

And then, of course, you have mergers and acquisitions leading to code being thrown away or warehoused or merged with other systems, or new management deciding to start from scratch.

Basically, the industry doesn't really have a long enough attention span to really make the most of OO code reuse.


People have long talked about how OO failed to generate code reuse, but I don't understand how they do it with a straight face. You reuse masses of OO code every time you write a non-trivial program using a modern standard library.

I think the people making this criticism are looking in the wrong place for the reuse, and / or had weird ideas of what could be reused, and how it could be reused, to begin with.

The reuse that OO gives us comes from raising the level of abstraction with which the program is written, in particular because runtime libraries are so much larger ("batteries included", etc.). The hierarchical namespaces and encapsulated structure of modern class libraries reduces their cognitive overhead. For example, in .NET, you can work with WebRequest, TcpClient or Socket, depending on what level of control you need; and the conventions for working with these things are pretty uniform across the board. Larger applications are self-similarly written at a higher level, reusing code within themselves in a framework-like way.

But the people who thought there was going to be some kind of central library of domain-specific classes in your company, that you would reuse in multiple disparate applications, I think that was always fairly naive; reuse implies coupling, and coupling of things that are individually subject to change in ways that affects their users is fraught with problems, and always has been.

The best candidates for reuse aren't usually representations of the domain concepts that are central to a business, because each application in the business will probably be wanting to do something quite unique with those domain classes. Rather, it's concepts that are self-contained, universal, not likely to change much over time nor need different intrinsic behaviour from application to application, which are best suited to reuse.


"You reuse masses of OO code every time you write a non-trivial program using a modern standard library."

How much of that is due to OO, though? I reuse masses of code without OO all the time.


The biggest problem with OO is the abuses. I recently worked with a large codebase where /none/ of the behaviour for objects was in the objects themselves. Some Architect had come along and beaten it out of them with an extreme application of the 'too many patterns' anti-pattern.

One way they justify this is to 'reduce coupling', and so your comment about coupling tripped a red flag for me. Whenever I want to take the piss out of an Architect I just tell them that we should 'add an extra layer of indirection' to the design. 99% of the time they agree without realising that I'm satirising them.


"where /none/ of the behaviour for objects was in the objects themselves"

Actually, this could be a good thing, depending on what the goals were. For example, non-member non-friend classes are often more OO than putting everything into the class[1]. Furthermore, if you want to use function overloading for multiple dispatch, the keeping the functions separate from the objects is also useful. If your system is highly concurrent, keeping the code and data separate can be quite helpful. Also keeping data in structure-of-arrays form and using external functions to operate on these arrays can make huge differences in terms of cache usage, potential parallelism and vectorization of instructions.

Coupling might be a reason to do this, but its certainly not the first reason I think of. There are plenty of better reasons (and as always, not all reasons apply to all codebases).

TL;DR: There are lots of reasons why doing this could be a good thing.

(fwiw, I like to do this with my core data structures because I believe code and data should be kept separate (and that data is the more important of the two). I do like to provide normal objects as an API though, because I often feel that its a natural interface, but the internals of my code are rarely very OO in the C++/Java sense).

[1] http://www.gotw.ca/gotw/084.htm


"But the people who thought there was going to be some kind of central library of domain-specific classes in your company, that you would reuse in multiple disparate applications, I think that was always fairly naive"

Well, perhaps, but I've seen it done successfully in NeXTSTEP/OpenStep shops back in the day, such as an investment bank. Not one big library, but a few frameworks so there's some separation.

The team I was on had our own frameworks, shared among the apps we developed. We also used/built our frameworks on frameworks from the bank's Architecture group, which were also used by other development groups.


I agree. I'm not a big fan of OO, preferring functional approaches in most cases, but I usually use some kind of OOP either to tie things together or to provide easy to use interfaces to the system, as I find constructing and passing objects to modules is often a natural way of interfacing with them, especially if the system is complex and the objects are used to "insert" code into the system (eg, algorithmic skeleton style). So even though I dislike OO as a whole, I think it has a very useful and important role in programming and it certainly helps us bring ever-more complex problems to a level we can reasonably deal with.

Having said that, there are some things OO is bad at, eg concurrency.


How does OO have any effect on concurrency? I'm genuinely curious here.


Mutable state.

OO prioritizes encapsulation ahead of immutability as a way of making the problem of a mutable struct tractable. Most OO programs are graphs (picture as a complex web) of mutable objects holding references to one another, synchronously passing control from one object's method to the next (picture as a spider travelling around the web, making modifications). Concurrency means there is more than one logical point of control flowing around the graph, making modifications. To ensure modifications are consistent, one must now fight against the interconnected nature of this graph, and make certain areas mutually exclusive; that means you need to set up gates on all the edges leading into those areas (often called semaphores or mutexes).

But OO gives you precious little help in setting aside these areas, and guaranteeing internal consistency in the face of multiple mutating points of control.

Programs in a functional style are different, with their heavy emphasis on immutability. In this case, the web, as it were, is fixed and cannot be changed; instead, if there is to be a modification, a new copy is created (possibly only of the local area of change, and the unchanged portion included via references). Since there is no way to change data, there can be as many points of control performing operations as desired. (Actually, one of the models of computation used for functional programs is that of graph reduction, which pictures the program as a web of expressions rather than structures; and that big expression is iteratively made smaller by calculating different parts of it. In principle, the more points of control you have doing these calculations, or reductions (in the same way as '1 + 2' can be reduced to '3'), the better.)

Programs written in an agent / actor style are also different. Here, there is no single point of control flowing from one node in the graph (web) to the next; instead, each node has its own little point of control, and it reacts to messages coming in from each edge, and sends out messages along edges in response. This makes the program locally single-threaded, but globally concurrent.


You said it better than I could have! :)


Code organization aside, how is OO any different from procedural programming with regards to concurrency?


I would say that procedural code is less inclined towards both immutability and encapsulation than OO; I would say to a first order approximation that it tends to be worse than OO for concurrency.

But there are moderating factors. Procedural programs that don't enforce strict modularity conventions tend to be bound in size by their complexity, a complexity that works against the level of understanding necessary to make things both concurrent and correct. Meanwhile, procedural programs that do enforce strict modularity will probably be using conventions that emulate a different paradigm, and will inherit that paradigms' costs and benefits WRT concurrency.


In 15 years of experience where Java sadly pays the bills, for example, systems written in that language that had a modeling approach that tended toward immutability and tended to limit the visibility of mutable state throughout the system were also more understandable, more amenable to change and therefore better than those that weren't. Irrespective of concurrency and parallelism!


Yes. Arguing that immutability is possible in Java, is a bit like arguing for good code in PHP. It's possible and advisable.

But Java naturally tends towards mutability. And you will have to work harder to make it immutable. Java also does not give you as many tools for this kind of style as functional languages usually give you.

First class functions, a rich type system and a library full of immutable data types come to my mind.


Also OOP (as seen in C++ and Java; the original ideas of passing messages to objects sounds like it would have suited concurrency a lot better) encourages mutable state. Sure, you can program with immutable state (and many people do - I certainly do), but it feels like its going somewhat against the grain of OOP in those languages.

Worse, OOP tends to hide the mutable state away internally in objects (or in objects stored inside objects etc) - OOP's data hiding and abstraction support can go against you here. Sure, good programming practices and discipline (eg, const correctness in C++) helps, but the languages definitely encourage mutable state.

I wonder how using methods-as-messages and turning OOP into a message passing system not dissimilar to the actor model would work in practice (both from a usability/syntax and concurrency view).


I'd say the biggest boost came from modules, and the control of side effects (by, among other things, limiting the use of global variables).

Now, do you see a significant additional boost that were provided by the various OO styles out there? More specifically, what significant advantage do classes have over modules?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: