18 ms·
Joe Armstrong: Why OO Sucks
- bithive123 14y agoA series of assertions and "I just don't see it"-s presented as self-evident when they are anything but. No examples of real cases where OO does in fact "suck", ending with the claim that in order to understand the popularity of OO one should "follow the money". What? I mean, I don't even...
- MortenK 14y agoIndeed, it's a very odd piece. No arguments except opinions ("state is bad", "functions and data shouldn't mix" etc). I fail to see the underlying reasoning for any of his gripes. It just comes of as a frustrated computer scientist / mathematician complaining that his theoretically correct way of making machines do his bidding, is not loved by all.
- comex 14y agoharmful.cat-v.org has a lot of odd opinions: http://harmful.cat-v.org/software/dynamic-linking/ http://harmful.cat-v.org/software/dynamic-linking/ http://harmful.cat-v.org/political-correctness/girls-in-CS http://harmful.cat-v.org/political-correctness/girls-in-CS
- arrakeen 14y agoi'd take anything i read at cat-v.org with a grain of salt, they seem to appreciate the art of trolling: http://gofy.cat-v.org http://gofy.cat-v.org
- masry 14y agoOFFTOPIC - Man I can't believe how often I am coming across "sexist in IT" stuff now. I read your second link and I thought to myself it all makes sense. Demanding that compsci have more women is like demanding [insert women dominated field here] have more men, even though most men just aren't interested in the stuff. Why bother? Why not just let people work on what they want to work on? Is this making me a sexist misogynistic jerk? I am not trolling, I am honestly curious. Explain to me why I am wrong. I will reflect and make up my mind and be intense and stuff.
- Locke1689 14y agoDynamic linking seems to be a rather straightforward technical argument. I'm not sure what to tell you if you can't or won't parse it.
- comex 14y agoI've had a conversation about it on HN in the past: http://news.ycombinator.com/item?id=4112517 http://news.ycombinator.com/item?id=4112517 I wouldn't mind discussing it again.
- einhverfr 14y agowhen zlib had that double-free bug a while back, how many programs had to be updated because of static linking? I think the problem is that in most of these cases, people only count one side of the ledger. On the whole, I think static linking causes more security issues than dynamic linking, but dynamic linking causes some other problems that are less well accounted for.
- rapala 14y agoA security hole in a library is "automatically distributed" to every program dynamically linked against it. Yes, the coin has two sides.
- einhverfr 14y agoI am not saying that dynamic linking is perfect. However, a lot of it comes down to how manageable is security. How many programs do I have to update? How sure am I as the sysadmin that I got them all? This is easier with dynamic linking than with something ubiquitous but often statically linked like zlib. Yeah there is a tradeoff. I am not saying there is no downside. I am just saying security-wise, I prefer a single-point-of-correction to a case where I may not know where the weakest link is.
- discussit 14y agoThe second link is to gibberish from reddit. Not sure if it's a joke or if it represents the opinions of cat-v. But the first link is on the money. I would not call it "odd" as that seems to carry a negative connotation. Rather, it's sensible, albeit irreverent, thinking to question dynamic linking (as the Plan 9 people have) and alas the mainstream of software development has a difficult time thinking sensibly and prefers to "follow the herd". Dynamic linking is anything but a clear "win", using the silly web lingo of today. It's one of those many engineering trade offs we continue to live with even though the original rationale for its adoption no longer exists. Here's the problem as I see it. You link to a library of n functions where, e.g., n > 10. But your program only uses 1 or 2 of those functions. There is no accounting method for keeping track of which functions each of those "4000" different binaries uses. How easy is it to tell me what functions each of those "4000" binaries uses, and which libraries they reside in? I have to resort to binutils hackery to extract this info, but it seems like basic information that should be easily available... because it should be used in making decisions. Why link to a library with, e.g., > 10 functions when your program only uses, e.g., 2 of them? How many functions in those libraries that your program links to are not used by your program? No big deal you say. And that's true. Because of dynamic linking. Dynamic linking to some degree makes us disregard this wasteful "black box" approach to use of library functions. But what if we started static linking? Then maybe we start to think more about those functions that are in the linked library but are not used. We might even question the whole idea of libraries. What if we took an accounting of all the unused functions? How much space would they account for? Why package functions together in libraries? Whatever the original reasons were for adopting this practice, do they still exist today? How many libraries do you have installed on your system that are only used by one or a few programs? Is there a threshhold for how many programs need to use a group of functions before it justifies creating a library tobe shared? If we really want to have functions that are to be shared among many disparate programs, and we have "4000" programs (cf. the no. of programs on a system in the 1980's) then it makes less sense to place them in arbitrary libraries (how many people know the location of every C fucntion purely based on library names intuition?) that have to be linked to as a unit. We perpetuate a black box. It makes more sense to have each function available on its own, and each program can select only those functions that it needs. This is if we were static linking. I do a lot of static linking because I move programs from system to system. It works very well. Another thing that I sometimes think about is the sticky bit. We try to achieve the same effect with caching. You call a program for the first time, it take some time to load. You call it a second time and hopefully it's all in the cache, and it is much more "responsive". But what if it cannot fit in the cache? What if another program displace it? Why can't we conscisouly keep a program in a "cache"? We give control to the OS, and we hope everything works as intended. Dynamic linking reminds me very much of package management systems, particularly those that build form source. It's extremely difficult to tell what a particular install procedure consists of. You type "make" and what happens next is in many respects a black box. Only so much information can be reliably extracted from the system. For example, if you wanted to know all the possible Makefile variables in the package management system, it's virtually impossible to get a list. You can get most, but not all. The way thse systems work is a lot like shared libraries. The mainatiners err on the side of overinclusion of dependencies, some of which may not actually be needed, in order to keep the black box working reliably.
- NinetyNine 14y agoThere's a certain allure to saying code should be a certain way because of natural properties of computing, or our own feelings on what things are different and similar from what other things. The reason OO shines is because it allows you to make that distinction at the domain level rather than the code level. You organize your software into business objects, or components, and have these interact with each other. They allow you to separate it out in a way that a new developer can come to the project, understand what the code should be doing, and look for the classes which seem the like objects involved, including the types of data it has and the things it can do. There are all sorts of nasty things we've invented in OO over the past few years (mixing up inheritance and composition, using way too much state), but it gives us a lot of advantages from an engineering point of view.
- stock_toaster 14y agoIsn't that a bit of a false dilemma though? Can you not have clean interfaces and separation of concerns without OO -- even with something as 'simple' as python namespaces and dicts?
- el_presidente 14y agoDicts are objects.
- stock_toaster 14y agoThat is an implementation detail due to python's object support. Dicts are a native type, that are hashmaps. Unless you mean "object" as in "a thing"....
- Maro 14y agoI think he means dicts combine data, state and functionality, expose a clean API and hide the details.
- pessimizer 14y agoOO isn't the only way to implement the Actor model.
- zacharyvoase 14y ago“Data structure and functions should not be bound together” — I can't agree with you more. However, in Smalltalk (and even Ruby, to some degree) objects are not data structures, they are collections of functions invokable on a 'thing' with an unknown structure. They have an internal structure—potentially immutable—but you never see this, because you only interact with methods on the object. And in many cases, there is syntactic sugar to make invocation of these methods look like slot access: think of Objective-C’s `@property`, or Python's descriptors, or Ruby's `def method=(value)`. When people talk about 'object-oriented languages' in such general terms I get frustrated, because there's a lot more nuance to this than simply 'bundles of functions and data structures'. That's a very implementation-led way of looking at it. The reality is that these objects are supposed to represent real-life situations where knowledge of what something is, or how it behaves, or how it fulfills its contracts is unknown. If NASA's Remote Agent[1] had been implemented in Haskell, OCaml or ML, do you think debugging DS1 would have been as simple as connecting to a REPL and changing some definitions in a living core? I don't think the image-based persistence of SmallTalk and many Lisps would be possible in a purely functional or traditional procedural language. And what is a data type anyway? It's supposed to represent a mathematical set of possible values. Sure, you can use a simple array to build a b-tree, but don't you want to explicitly state that variable x is a b-tree if that's the case? I was always taught that explicit is better than implicit. I should probably stop ranting now, it's just that if you’re going to start hating on programming paradigms, at least sound like you've thought your argument through a bit more. [1]: http://www.flownet.com/gat/jpl-lisp.html http://www.flownet.com/gat/jpl-lisp.html
- m0th87 14y ago"If NASA's Remote Agent[1] had been implemented in Haskell, OCaml or ML, do you think debugging DS1 would have been as simple as connecting to a REPL and changing some definitions in a living core?" Erlang in particular is known for rock-solid support for this, and Armstrong never advocated for pure functional languages. "Sure, you can use a simple array to build a b-tree, but don't you want to explicitly state that variable x is a b-tree if that's the case?" You can do this in Erlang with atoms.
- joe_the_user 14y ago
- programminggeek 14y agoI think OOP took off because it seems like a great way to model things. The idea that you can simulate a car by saying you have a base kind of car with properties and actions and then a Ferrari is a kind of car, so you can just kind of take that car object and make it have more horsepower and a different body type and you have a Ferrari, is very exciting. Businesses like to model things and simulate things. So, in that respect, OOP was probably an easy sell because it's selling an idea of what businesses want, even if it hasn't worked out exactly as they hoped in all cases.
- ww520 14y agoI don't get it. If people don't like OO, why don't they just not use it. Just use your favorite methodology to get the job done. Why do they have to bad mouth it?
- i_cannot_hack 14y agoBecause they want to promote discussion and exchange opinions, and maybe advice others against something that they think is a bad idea. To just silently avoid stuff is a very stifling and unproductive way to handle things. They do not badmouth OOP. It is not a human being with reputation and feelings. They criticize its usage.
- mattacular 14y agoBut he is criticizing the design and fundamentals of OOP. Something doesn't have to be human or have a reputation to be badmouthed...
- it 14y agoIf we fail to point out the harmful effects of excessive OO usage then there is a higher likelihood of encountering it as legacy code written by people who didn't know any better. This can lead to wasted time and decreased job satisfaction.
- deleted 14y ago[deleted]
- stonemetal 14y agoHe is the father of Erlang, so he did Just use your favorite methodology to get the job done. already. Why do they have to bad mouth it? Advertising, of the hey come check out my oil, it is so much better than your regular oil verity.
- glassx 14y agoI don't know the context of the post, but remember that Erlang is a community effort, not a dictatorship. He has to expose his arguments and motives in order to keep using his favourite methodology.
- dgreensp 14y agoOO vs. FP is just a matter of whether you focus the nouns or the verbs. The counterargument to the OP is that surely a function that manipulates "data" is less powerful and abstract than one that manipulates objects. For example, take an "interface" or abstract data type like Array, consisting of a length() and a get(i) method. (This is really called List in Java and Seq in Scala.) There may even be an associated type, A, such that all items are of type A. This is very powerful because functions written against the Array interface don't depend on the implementation; we can store the data different ways, calculated it on demand, etc. The "binding together" Joe is complaining about is binding the implementation of length() and get(i) to the implementation of the data structure, which is surely understandable. The alternative, seen in Lisps and other "verb-oriented" languages, is that there is a global function called "length" which takes an object... er, a value... and desperately tries to figure out how to measure its length properly, perhaps with a giant conditional. The original OO (SmallTalk) was about message passing rather than abstract data types; just the idea that an object was responsible for responding to certain messages, and that these communication patterns completely characterized the object. This is how we think about modern cloud services, too; it's kind of inevitable. Who would complain that S3's "functions" and "data" are too coupled? Who would ask for a description of S3 in terms of what sequence of calls to car and cdr it makes internally? OO concepts allow a functional description of a system that starts at the top and can stop at any point. The "everything is an object" philosophy gets a bad rap. It's a big pain in Java, especially, because of how the type system works. Ideally I'd be able to define a type of ints between 1 and 3, an obvious subclass of ints in general, whereas in Java I find myself declaring "class [or enum] IntBetweenOneAndThree" or some nonsense.
- klodolph 14y agoYes, a Lisp-like language could use a giant conditional for a generic "length" function. But that's not how the source code usually looks, and there are Lisp compilers which optimize it so it's not done as a conditional. In CLOS, it will look as a separate DEFMETHOD for each type you want to define the function on, and these can be in separate modules. DEFMETHOD will just extend the generic function. And the function itself can be optimized to use the normal tricks -- things kind of like vtables -- to optimize performance. The S3 example is a bit facile since (1) S3 objects are like mud, they're all the same and (2) they map cleanly to the OO paradigm since they encapsulate discrete chunks of external state. At the other end we can throw around examples like BLAS and LAPACK, whose functions are much closer to the "functional ideal" (ignoring mutability, here). For example, if I want to solve a linear equation, how do I express that as a single dispatch method? Does it go on the matrix, or on the vector? Or do I have to create a new object from the two called LinearSystem, just so I can invoke a single method? We think about things in terms of coupled data, as pure functions, and as dirty generic functions (like the Lisp example). The only real lesson is that people get pissed off at languages that force them to shoehorn everything into one category (like Java).
- borplk 14y agoFrom a purely scientific view, OO is a terrible idea because it moves the program further away from the mathematical form and makes it harder (if not impossible) to say, logically prove the correctness of the program. But from a practical perspective OO is a great idea because it makes many things so much easier.
- yen223 14y ago"But from a practical perspective OO is a great idea because it makes many things so much easier." This seems true at first, but after having worked with C# a while I'm not so sure about that. OO introduces some weird issues that aren't immediately apparent: 1. Verbosity When the shortest method call looks like "abcObject.functionXYZ()", code gets huge really fast character-wise. This actually does make it harder to read and debug existing code. 2. Multithreading Multithreading in any programming paradigm is a pain, I'd give you that. But OO exacerbates the problem because of the way each property of an object is essentially a global state within its local scope. It makes it quite tricky to enforce thread safety. Having said that, I'm not sure that rewriting it in, say, a functional style would make things simpler. Sure it is easier to prove correctness, but as soon as you introduce IOs, everything goes to hell. I guess OO seems to be the worst pattern, except for all others that have been tried.
- borplk 14y agoI think the advantage of OO is that is transforms the code into something that is closer to the "human" interpretation. Modelling the problem like we have it in real world. Instead of thinking like a computer, you can more easily think as a human and let the computer do the rest. Although of course it comes with trade offs.
- icebraining 14y agoI don't think verbosity is an issue with OO any more than it is with any other paradigm. 'abcObject.functionXYZ()' is not any more verbose than 'functionXYZ(abcDataStructure)'. I think it's mostly a question of the community's coding style, and C♯ and Java are notoriously verbose even in their standard library.
- einhverfr 14y agoI see a bunch of caveats here. The basic issue is that OOP is easily hyped and far too easily taken too far. My favorite OOP environments are decidedly un-OOP in specific ways (Moose, for example, has very transparent data structures, which is really useful). The first big criticism I have is with the idea that "state is the root of all evil." I think the truth is more nuanced than that. State is, in many cases, extremely necessary to track. The problem is that state errors create bugs that are very difficult to track down (you can eventually figure the state out, but how did it get corrupted)? A better approach I think is for state to be approached declaratively and with constraints. This is why things like foreign keys, check constraints, etc. in the RDBMS world are so nice. In fact good db design usually has a lot to do with eliminating possible state errors. Wouldn't it be great if OOP environments gave that possibility! Well, Moose does to a large extent (another thing I really like about it). A lot of it comes down to the really hard question of "what should be abstracted?" The correct answer is a question, "what makes your API most usable?" This is why I think it's important to be able to move in and out of the OOP worlds, and why OOP taken too far runs into the problems the author mentions, but that it also doesn't have to.
- alttab 14y agoWhat about the benefits of abstraction? I'm not going to introduce hyperbole on how I think this article is overstated, and instead I'm going to ask HN members who have more experience with functional programming how they leverage concepts similar to abstraction with Haskell, clojure, or erlang, etc?
- ef4 14y ago> What about the benefits of abstraction? You seem to have a strangely narrow definition of "abstraction". Start here: http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-4.html#%_toc_start http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-4.html#...
- zaphar 14y agoAbstraction: * Haskell typeclasses * Clojure Protocols, Multimethods * Erlang Processes Abstraction is not limited to Objects. Objects are just one way of expressing abstractions.
- alttab 14y agoThank you. This gave me enoug keywords to do some good research. Now clearly these methods could even be applied to ruby and other oo enabled languages as well
- tikhonj 14y agoIt's funny you should mention that--it seems Haskell usually gets accused of being too abstract. In Haskell, it's actually common to write very abstract code. In fact, I think that is one reason why Haskell is tricky to pick up at first. OO "abstraction" is never that abstract--you can always tie it down to some concrete thing or idea. An iterable is obviously something you can iterate over, and that's about as abstract as you get. Haskell, instead, finds its core abstractions in math. It uses ideas from abstract algebra and category theory that are more general than anything I've seen in OO. The core abstractions like the infamous monads, functors, monoids, arrows and so on are not easy to tie down to anything concrete at all. For example, the standard functions that work on monads (like foldM) can work on a dizzying array of different types: functions, lists, nullables, continuations, errors, parsers, ASTs. Any given function like this does the same thing parametrized by the behavior of the type in question: so foldM always does a fold, but the exact behavior depends on the exact monad being used to do the folding. And there is no obvious relationship between the different behaviors that can be modelled this way. In short: Haskell uses ideas from math to get very abstract code, for better or worse. These mathematical concepts can model a gigantic amount of different things which, intuitively, may not seem related at first.
- msluyter 14y agoI expect this to be a busy thread. I think the point about state has some traction. For example, Chaper 15 of Effective Java (awesome book on Java, btw) is entitled "Minimize Mutability," so I think this idea is one that has caught on even in fairly traditional OO languages. As for the other points... I do think sometimes that using OO to model real world objects may not always be wise, esp. if the result is a deep hierarchy, as in the OO 101 example of, say, Boston Terrier < Dog < Mammal < Animal < Thing... And then someone changes Dog and gives your Boston a tail... I dunno. I have only vague intuitions here, but perhaps the "objects as models of reality" might be perfectly suited for reality simulators of some sort that require stateful elements a la Sim City but not generally. Or, perhaps a better example: You could model a chess game as classes of Pieces on a Board, with methods like King.isInCheck(), or Queen.canMoveTo(Square) but this to me seems clumsier than simply having an 8x8 array of enums with the logic living in functions and not inside individual pieces.
- ioquatix 14y agoLanguages that are "OO" and languages that are not (in this case functions and data structures) are semantically equivalent. Q.E.D.
- it 14y agoIt is possible in principle to implement one in terms of the other, but in practice this is not what typically happens.
- ioquatix 14y agoSure, it might not be typical, but it does happen in quite a few languages. CLOS is one system that comes to mind. FP vs OO is an interesting discussion but this article hardly does it justice.
- notJim 14y ago99% of the time I read these articles that say $commonly_used_thing [1] sucks, the arguments are always "it is fundamentally incorrect" or some variant thereof [2], and strawmen [3] abound. Where these arguments fall short are in addressing the simple fact that highly-skilled people produce very neat, well-designed systems that they are pretty happy with from a technical standpoint, and that make money every single day using $commonly_used_thing. If you can't acknowledge that $commonly_used_thing has some good attributes, and that it actually works well for many cases, I don't understand why I should take you seriously. [1]: Examples of commonly_used_thing: ORMs, OOP, SQL databases, NoSQL databases, operating systems, platforms. [2]: There are a handful of variants. I think my favorite is the magical phrase "impedance mismatch", which I think in non-buzzword-speak translates to "fuck you, I'm right" [3]: Most-frequent strawman: the most essentialist, rigidly-formal version of $commonly_used_thing, when in reality, nearly every version of $commonly_used_thing compromises to cope with reality.
- LnxPrgr3 14y agoEvery time someone says $commonly_used_thing sucks, people come out and point out that $commonly_used_thing is being used for $productive_activity. It is possible to do amazing work with broken tools, or with the wrong tools. That doesn't mean these tools aren't broken or that they couldn't be better matched to the job. Not that I think OOP is inherently evil. Reading the article, I don't think the author quite understands OOP. One example: "In an OOPL I have to choose some base object in which I will define the ubiquitous data structure, all other objects that want to use this data structure must inherit this object." If he really believes this, no wonder he's railing against OOP. That would be horribly broken.
- notJim 14y agoI essentially agree with what you're saying, although in most cases, I would argue against the characterization of the tool as "broken". But I think that's semantics. If this article was titled "Functional programming offers a number of advantages over OOP when dealing with $productive_activity"[1], my response would have been positive. [1]: It goes without saying that the article would have to live up to the title. Obviously merely re-titling this article in such a way wouldn't be sufficient.
- lukifer 14y agoOO is just one design pattern of many; it should be used when the mental model is a good fit for the problem domain. It does annoy me, though, when languages or frameworks force the use OO when it's unneeded. Use a function when you need a function, and a class when you need a class.
- carsongross 14y agoI find grouping functional code along with the data the code is supposed to work on reasonably intuitive. The OO religionists definitely sold the world a bill of goods on the reuse arguments, and the religious fervor was silly (just like it is with todays functional zealots) but still. Having an 'x' and hitting '.' and seeing what 'x' knows to do with itself doesn't suck.
- nessus42 14y agoI've been watching some talks online recently by Rich Hickey of Clojure fame, and he's a very interesting and convincing speaker. He basically makes the same argument that Armstrong makes here. I'm not clear, however, how the pro-FP, anti-OO crowd address the Law of Demeter, which is often summarized as "One dot: good. Two dots: bad." The canonical example where the Law of Demeter serves us well comes from some of the original Demeter papers, which I actually read a long time ago when they were current. This canonical example is that of an object to represent a book. One of the initial selling points of OO was that if you encapsulate the representation of an object from its interface, this ends up giving you a lot more flexibility. For the case of representing a book, pre-Demeter, a typical OO organization would have been to provide a method to give you chapters of the book as Chapter objects, and from there you could get Section objects, from which you could get Paragraph objects, from which you could get Sentence objects, from which you could extract the words as strings. The Demeter proponents correctly argued that this OO organization of the Book rather defeats the goal of encapsulation, since with this organization you cannot restructure the internals of the Book object without breaking the API. E.g., if you decide to insert Subsections between Sections and Paragraphs, your API for extracting all the sentences of a book will change, and consequently, much of the client code will have to change. The Demeter folks argued that instead of having to explicitly navigate to sentences, you should just be able to call a method on the Book object directly to get all the sentences. Without special tools, however, this is hard for the implementers of Book, since now they have to write tons of little delegation methods. I take it that people who are serious about following the Law of Demeter do do this, however. In the original Demeter system, Demeter would do this automatically for you. The problem with the original Demeter system is that few people actually ever used it, and it was rather complicated for Demeter to provide this automatic navigation. So, back to FP: Rich Hickey argues to forgo damned objects and to just let the data be data. So if I follow Hickey's advice, how am I supposed to represent a book? As a vector of vectors of vectors of vectors of strings? If so, then how do I prevent a change in the representation of the Book from breaking client code? If I had followed the Law of Demeter with OO, then everything would be golden. Sure, with this naive FP approach, I could also provide a zillion functions to fetch different sub-structures out of the book. E.g., I could have a function to return all the sections in a specified chapter, and another to return all of the sentences in the book. This, however, would end up being little different from the OO approach following the Law of Demeter, with the further downside that if you change the representation of the book, you don't know that you haven't broken the client code, because you have no guarantee that the client code isn't accessing the representation directly. Please advise.
- 6ren 14y ago- though he has no qualms about misleading and deceptive answers. - "If I understand the input and the output then I have understood the function." A good point, I tend to think of "information hiding" http://en.wikipedia.org/wiki/Information_hiding http://en.wikipedia.org/wiki/Information_hiding as applying to state, to enable SOTSOG, but it also applies to pure functions. - "define all my data types in a single include file" That quote sounds silly, but in practice, I find it much clearer if all the part of a data type are next to each other, uncluttered by methods. It also supports Brooks' observation: "Show me your tables, and I won't usually need your flowcharts; they'll be obvious" ("tables" being datastructures). In Java, I tried this by defining fields in superclasses, methods in subclasses. But having two classes per class was awkward. (I ended up keeping code entirely separate except for very core methods - still not happy with it). But I don't think this is entirely a language problem, it's partly just complexity management is hard. - this article makes me feel antagonistic, but in fact I never liked OO when taught it; it seemed dogmatic, not actually useful in practice. But I did like the idea of an ADT, where you can package something up (esp. a list, hashtable etc), and work at a higher level of abstraction. Subdividing tasks and SOTSOG
- nirvana 14y agoI can express my OO ideas in erlang with no problem (objects become processes). I cannot express my concurrency ideas-- that erlang makes super easy-- in the OO languages. Maybe Go changes this but I haven't used Go yet.
- glassx 14y agoAgreed. And Joe Armstrong himself used this argument here: http://www.infoq.com/interviews/johnson-armstrong-oop http://www.infoq.com/interviews/johnson-armstrong-oop
- Ingaz 14y agoAgreed that processes in Erlang is even better objects than objects in OOP. >>I cannot express my concurrency ideas-- that erlang makes super easy-- in the OO languages. In fact main Erlang ideas are many times "stolen". I discover Erlang in: Scala (obvious), F# (also obvious), D (also obvious). Actors + messaging = "DIY Erlang". Although I do not know a language that makes code hotswapping as fundamental feature.
- MarkMc 14y agoWow, I am genuinely shocked by the comments in this thread. I didn't realise that so many people held the polar opposite view to me. It's a bit like suddenly finding out that all your friends are racist. I love object oriented programming. For me it aligns perfectly with the way I think - it allows me to produce a system of interrelated 'things' where each thing (or group of things) has a well-defined role and can hide its internal state and behaviour from other things. When I see how some code tackles a problem I get an emotional response from how 'clean' it is. Does it smell bad or is it a work of beauty and elegance? If the code feels wrong I get an urge to make it better and for me that process of improvement relies heavily on object-oriented concepts. I get a real buzz from creating a clean, elegant solution to a problem: Trying to do that without object-oriented features would be like trying to write a letter by holding the pen with my teeth. Ugh.
- pacala 14y agoYou may enjoy learning a language with decent module system. Abstract APIs are not exclusive to OO. The confusing part about OO is that it conflates modules with data types, which causes even experienced people to botch their designs. Tongue in cheek: As long as you have enough discipline to write OCaml in whatever OO language your project happens to use, you are going to have a good time.
- seanmcdirmid 14y agoI'm also an object luver; I prefer to think about my designs in objects in a very anthropomorphic way. There are plenty of examples of bad and good designs in any language, while any paradigm is not a panacea. Bad OOP designs only dominate the industry b/c OOP dominates. You can build some beautiful systems with a functional programming language, especially if you are into formal mathematical elegance, I've ween some amazing things done with Haskell. But the systems I work with are very intrinsically stateful; objects just work better.
- fauigerzigerk 14y agoSo what is the natural and clean design for an operation that represents the sale of a property? Say we have these objects: the buyer, the seller, the agent, the property and the contract. Which one of these would you prefer? property.sell(buyer, seller, agent, contract) seller.sell(property, buyer, agent, contract) buyer.buy(property, seller, agent, contract) agent.sell(property, buyer, seller, contract) contract.sign(property, buyer, seller, agent) The state of all the objects may be modified, and there are different types of properties, buyers, sellers and agents. So you might want polymorphism along any of those hierarchies.
- LnxPrgr3 14y agoI'm all for proper rants against popular tools to keep people on their toes. This isn't one of those. "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." Sure—a class defines a type and operations on that type. What's fundamentally wrong about date.addDays(1) vs. date_add_days(date, 1)? (Let's skip the mutable state argument and assume both versions return a new date.) There is the problem that sufficiently opaque classes are hard or impossible to extend. That's the class author's fault: this is an avoidable problem in every object-oriented language I've used. "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. … Functions are usually 'understood' by observing that they are the things in a computational system whose job is to transfer data structures of type T1 into data structure of type T2." A constructor is a black box that converts a data structure of type T1 into a data structure of type T2. Objects just also have other black box functions defined on them. Sure, some objects are stateful, but they don't have to be. "In an OOPL I have to choose some base object in which I will define the ubiquitous data structure, all other objects that want to use this data structure must inherit this object." Um, no. This is a job for composition, not inheritance. "Instead of revealing the state and trying to find ways to minimise (sic) the nuisance of state, they hide it away." They hide state's implementation, for mutable objects. std::vector<std::string> some_list; std::cout << "Items: " << some_list.size() << std::endl; some_list.push_back("Hello, world!"); std::cout << "Items: " << some_list.size() << std::endl; // Oh no! State, EXPOSED! Sure, an allocated piece of memory might have grown, or even moved. Why should I care? I still see the state I care about, presented through a hopefully useful abstraction. This rant seems to somehow miss the points of both object-oriented and functional programming, instead harping on mostly meaningless (or outright wrong) details. Or am I missing something here?
- LnxPrgr3 14y agoI owe the author an apology on one point. "Minimise" is a correct spelling, though neither my system's dictionary or I realized this.
- 14y ago
- pacala 14y agoThe historical win of OO was polymorphism. The competition to OO was procedural code that consist(s|ed) of hardwired procedure calls. Enter polymorphism, which provides a way to abstract over functions, not only over values. Of course, this is nothing new to functional programming where functions are first class citizens, but it's new for procedural programming. Modern OO is about stateless objects, dependency injection and unit testing, aka functional programming.
- hurshp 14y agoWhat I find so obtrusive about OOP which I feel is a massive issue (maybe has to do with the last sentence in Joe's post). OOP is pushed into places it does not belong and causes a lot of impedance issues. OOP developers want if something doesn't talk OOP then to make it talk OOP, for example ORM's and SQL databases. It is a tables and sets, most of computers use sets and tuples, yet OOP needs to be serialized and abstracted away and pushed in almost becoming a data type in it's self. And I think there are other issues and pervious failures like this.
- deleted 14y ago[deleted]
- nivertech 14y agoWhile I dislike OOP, I think that CLU-style ADT has some merits, especially when ADT implemented in pure functional way. Just because you don't have explicit schema, doesn't mean that you have no implicit schema. Likewise just because you don't have explicit objects and classes, doesn't mean that you have no implicit objects and classes. I code in Erlang, and I treat every gen_server either as a singleton object or as a class (in case I spawn many instances of it)
- nessus42 14y agoWow, CLU! Those were the days!
- CurtMonash 14y agoHis history is wrong. OO won in large part for a good reason -- it was a way of implementing, if not enforcing, modularity. One that people accepted, unlike LISP.
- artsrc 14y agoI like modules that are more like objects. I would like to supply parameters to their constructors and be able to refer to them via names. Languages without modules, like JavaScript, support that kind of thing. http://wadler.blogspot.com.au/2009/08/objects-as-modules-in-newspeak.html http://wadler.blogspot.com.au/2009/08/objects-as-modules-in-...
- damian2000 14y agoIn the 1990's I saw OO as just another tool which was infinitely better than what I had at the time. I hazard a guess that most devs at the time were still working with procedural languages like C, Cobol, Fortran, Pascal or Basic. OO gave you abstraction and encapsulation, making it a little easier to write better code, that's all. For me it was never OO v.s. FP, it was just OO v.s. the status quo. If OO was hyped up so some guys could make money from it (as the article suggests), then who was behind it? -- Bjarne Stroustrup, Anders Hejlsberg or James Gosling? I think not.
- lightblade 14y agoWhat I finds funny is that all these OO design patterns and best practices are aimed to solve problems that doesn't exist in FP. Of course I may be over generalizing, but you get my point.
- ColinWright 14y agoThere was a substantial discussion when this was submitted 3 1/2 years ago: http://news.ycombinator.com/item?id=474919 http://news.ycombinator.com/item?id=474919 I do wonder if this discussion repeats all the same points, or if it raises new ones.
- yason 14y agoMy sentiments exactly couldn't have been better put than the author did in the opening sentence: When I was first introduced to the idea of OOP I was skeptical but didn't know why - it just felt "wrong".
- Tloewald 14y agoThe whole basis of this argument is that functions and data structures should not be "locked in a cage together". Replace object with "file" in the entire article and you'd have an equally but more obviously ridiculous argument. Does OOP have problems? Sure. Is Erlang great in some ways? Sure. But this argument is silly.
- timruffles 14y agoI think a project along the lines of Todo MVC for general programming languages - https://github.com/addyosmani/todomvc/ https://github.com/addyosmani/todomvc/ - would work really well for illustrating these kind of debates. Ideally it'd be a reasonably involved problem domain (rather than a todo list) with persistance, networking and something which requires parallelism/concurrency (I'm sure there are other categories too). This'd expose each language to the types of complexity that exposes the really interesting differences - does language X allow a clean API even when we require immutability for parallelism, does language Y impose boiler plate on simple problems, Z require unreadable line noise? I find these debates nearly useless without evidence and code to read.
- phleet 14y agoSo I have very limited experience with FP, and a reasonable amount with OO (mostly dynamically typed). I can really see the benefits of FP, but there are some problems I have trouble modelling with FP. For instance, if I have a simple 2D rendering engine, I just want to say "add this object to the screen". The object might be a geometric primitive (square, circle, etc.), it might be generated particles, or it might be an image or video or something. The way I deal with this at the moment is have Drawable or something to add to the screen with something like, which implements an interface with a "draw" method. screen.addToScene(new Circle(...)) screen.addToScene(new Square(...)) screen.addToScene(new ParticleGenerator(...)) screen.addToScene(new ImageSprite(...)) Then the game would loop over each of the Drawables, then call .draw() on them, which is implemented differently for everything that implements Drawable. How would I model this in FP? The only solution I can think of at the moment is to have a draw function that does pattern matching on the type of thing and do it that way. How do people do stuff like this in scheme or other languages with limited support for pattern matching? The problem I have with this is that it means every time I want to add a new kind of thing, if it implements many methods in an interface, I have to go to many different files to implement how this new kind of thing works. Among other things, that's a huge pain for revision control, since if I have 3 coworkers adding new kinds of things that can be drawn, we're all going to have to modify the draw function. In OO, we'd each just be creating a new subclass in its own new isolated file. As a second question - what should I read to get a good idea of how to sanely model things in OO and FP? I've read a lot of debate about the right way of doing things, but I don't really know where to learn this stuff. The OO class in university was completely useless, since the examples were outrageously contrived and too small to see any real benefits. I'd ideally be looking for 1 book that explains how to model real problems in OO very clearly, and one book for how to model real problems in FP.
- aaronharnly 14y agoI encourage you to read Philip Wadler's essay The Expression Problem, which addressed precisely the dilemma you point out: http://www.daimi.au.dk/~madst/tool/papers/expression.txt http://www.daimi.au.dk/~madst/tool/papers/expression.txt In brief, if you think of data types are rows, and behaviors as columns, the question is how to extend either the rows or the columns naturally. In your example, it is easy to add a new row (datatype) – create a Triangle class which implements the Drawable interface. It is difficult to add a new column (behavior) – if you realize all of these datatypes should also have a "extrude to additional dimension" behavior, you're going to have to individually implement that in all of your different classes, across many different files, etc. All of the problems that you note arise when adding a new datatype in the FP strawman. It's important to recognize that this is indeed a difficult problem, and that addressing it well takes real care. The c2 wiki has a good distillation: http://c2.com/cgi/wiki?ExpressionProblem http://c2.com/cgi/wiki?ExpressionProblem and this paper (by the Scala people) is very nice: http://www.scala-lang.org/docu/files/IC_TECH_REPORT_200433.pdf http://www.scala-lang.org/docu/files/IC_TECH_REPORT_200433.p... Some approaches that languages take, to varying degrees of success, include typeclasses in Haskell, multimethods in Clojure and elsewhere, the Visitor or Extended Visitor patterns in OO languages, controllable extensions in C#, Ruby, and Scala, etc.
- jroseattle 14y agoThe conversation around programmatic semantics and languages and the like always come and go over time, and feelings about them ebb and flow. Over umpteen years as a developer, I can say that I've found there's something about every language that will cause one to say "why do I have to think about this like that?" Nothing is perfect, but certainly a lot of languages do a few things quite well. As such, I would be grateful to hear an argument of why object-oriented programming structures are incorrect. I disagree with the reasons provided by the OP because of the slant toward personal preference. The arguments posted here are specious; I can find holes in each of the points made. 1. Data structure and functions should not be bound together - very true, they should be independent. However, this statement: "Objects bind functions and data structures together in indivisible units." This implies how something is implemented (or rather ALWAYS implemented), and while a tight binding is possible in most OO-supporting languages, it's not requisite. Just because the ability to violate this exists doesn't make it awful; it just makes it complicit on the programmer to use the right approach in a given situation. 2. Everything has to be an object - in some languages, this is true. However, this causes what problems? For the OP, this is nothing more than semantical ickiness. I won't defend any implementation of things like time and date and other primitives, but the chief complaint here seems to be how that information is accessed and the form of which it takes. I simply find the "this-is-an-object-so-it-feels-wrong" argument quite lacking. 3. In an OOPL data type definitions are spread out all over the place - this is organizational, but I'm not sure what "find" means in context. I guess it depends on the language being used, but I question why this is an issue for the OP. "In Erlang or C I can define all my data types in a single include file or data dictionary." I can do the same thing in Java or C# or other languages, if I want. For most developers, "finding" data type definitions has more to do with documentation than the actual language. 4. Objects have private state - of course they do, it's the nature of OOP. This statement: "State is the root of all evil. In particular functions with side effects should be avoided." This is unfounded (not the side effects part, which has nothing to do with state.) State, as the OP points out, exists in reality but should be eliminated from programming. Just as the bank example points out, one will want state to be accounted for in cases of deposits and withdrawals from an account. Thinking that state can only be handled in a certain way (which is what this argument suggests) is limiting in evaluation and unimaginative in assessment. Most of the arguments show personal preference to application development, and with that I totally understand. But these arguments are intended to show why the languages which support OO are conceptually wrong, as if the concepts of the alternative are an accepted truism.
- erlkonig 14y agoHeh. The "-deftype second() = 1..60." is a problem, since some minutes have 61 seconds in them.
- gabordemooij 14y agoTo me object oriented programming makes a program 'come to life'. In our daily lives we are surrounded by objects: trees, houses, books... to name just a few... I love the fact that I can reason about these 'natural' concepts in my code. Thinking 'in objects' sparks my creativity and boosts my imagination. It helps me to visualize otherwise very abstract notions. I love to talk about a 'Book' instead of an Array. With good Object Oriented code, technical concepts and natural ideas seem to come together. To me, the benefits of writing object oriented code have more to do with human-computer symbiosis ( http://en.wikipedia.org/wiki/Smalltalk http://en.wikipedia.org/wiki/Smalltalk ) than with pure technical correctness, it just fits my mind. If you want to appreciate the real beauty of objects I recommend to skip Java and C++ for a minute and look at Smalltalk. I just read the Blue Book (Smalltalk-80) and I had tears in my eyes. The elegance and beauty of this language is just stunning.
- michaelochurch 14y agoThe people who originally came up with OOP knew what they were doing. The inspiration was the cell, which hides immense mechanical complexity behind a simpler interface of electrical and chemical signals. When interfaces are simple, it limits the unexpected dependencies that can exist between software modules. Alan Kay wasn't saying, "Go off and write bloated objects" but, "When software must be complex, strive to provide simple APIs." For example, when you write a SQL query, do you have to micromanage the database in how it's performed? No. That's an example of encapsulation. The implementations are different, but the interface is fairly stable. That's something OOP-like that works very well-- an interface that hides (encapsulates) complexity. Objects are general and powerful, and that's part of the problem. "Power" isn't always good; GOTO is also extremely powerful, but should be used sparingly. Objects are not specific. Is it a function, or a tangle of methods, or a data object, or a "singleton" module? This isn't clear, and it becomes even less clear in the industrial world where tens of hands pass over code and it turns into mashed potatoes. There are some good ideas in "object-oriented programming", but it's also an extremely complicated programming model and it's hard to develop OOP code correctly. If you don't know what "open recursion" is and why it's dangerous, you shouldn't be doing OOP. What happened in the 1990s is that there was an effort (now becoming acknowledged as a failure) to commoditize programming talent-- to make 5 mediocre programmers able to replace a great one, and thereby prevent what we see now (the long-term "threat" of top software engineers outclassing professional managers in social status and compensation). Thus was born a bunch of design-pattern cargo-cult stuff designed to make programming slow, tedious, and limited but easy enough that mediocre people could do it, if they were stacked on top of each other in large enough numbers. Thus were born bloated, horrible codebases that bastardized "object-oriented programming" beyond imagination-- 21st-century spaghetti code. People should be required to learn the basics of programming first. They should start with immutable data objects, referentially transparent functions. Mutable reference cells can come next as an optimization. Then, it's a good idea to learn type systems through OCaml or Haskell. After that, they can tackle the hybrid OO/FP of Scala. (Once you've learned Scala, there's no reason to use Java unless you need performance.) There are times to use OO and times to use FP, but if you aren't smart or curious or dedicated enough to grok FP, then you'll never actually understand OO either and you have no business trying to use it. People learn best when they're presented with one new concept at a time, and the problem with OOP is that it presents tens of new concepts at the same time, with no separation. It leads to cargo-cult programming because people start coupling concepts that don't necessarily belong together.
- kyledrake 14y ago"Reason 2 - It was thought to make code reuse easier. I see no evidence of 1 and 2." https://rubygems.org/stats https://rubygems.org/stats
- astrange 14y agoCode reuse works at the library level, not the individual object level. You're not exactly fishing an object out of a worldwide sea of classes there. Actually, immutability can code reuse pretty easy, but many OO systems make no effort to encourage that (one reason Python is not my favorite language).
- Locke1689 14y agoFundamentally I think OOP is either state or syntactic sugar. If your methods don't modify internal state then they're basically doing ad hoc type polymorphism on their first argument (this is the way that virtual methods are implemented, by the way), which just makes the '.' syntactic sugar that at the same time limits composibility because it demands an inheritance hierarchy. Then it just comes down to whether or not you believe that mutable state is a good design choice. I don't. I think state is the root of all evil. For one, it makes my job as a PL researcher of 1) writing a formal analysis and 2) using the formal analysis to write a compiler, less attractive than blowing my brains out. Note that you can have objects without OOP. Python has objects. Python is not object-oriented. Same with O'Caml or Racket. I'm not arguing against using state. If you're programming a state machine, you may want to model it with state. That would be a pretty good choice. The problem is that OOP says everything is a state machine. Do you believe that or not? Either way, I'm putting my best efforts towards state-corralled languages.
- vph 14y agodata structures and functions are very much related and connected. In fact, all data structures are invented to perform certain specific functions. OO is not the answer to all things, but it provides a natural way to fuse data structures and its associated functions together.
- tikhonj 14y agoIn this case, "function" means mathematical function rather than purpose. Of course, if you want to take a somewhat reductionist approach, you could argue that data structures are functions. After all, in the lambda calculus, all you have are functions and you can use them represent numbers, pairs, lists, booleans, conditionals--basically whatever you want.
- jongraehl 14y agoAuthor does not understand OO, or argues against strawman OO: > In an OOPL I have to choose some base object in which I will define the ubiquitous data structure, all other objects that want to use this data structure must inherit this object.
- sodelate 14y agooo is not always the better choice
- bborud 14y agoIt would be useful if Armstrong stated which languages and which programming styles he disagreed with. "OO" is too vague. Not only does it include languages as different as JavaScript, Perl, C++ and Java, but there are wildly different ways of using each of these languages. For instance it is entirely possible to write purely functional code in JavaScript if you want to.