1. 21
  1. 10

    A lot of his argument seems to be “OOP doesn’t help with complexity because you can get all the features in other ways.” Which is true but not really that relevant. First of all, a lot of the “other ways” are going to have different tradeoffs. Like “leading underscore in Python” or “code documentation” aren’t nearly as good at information hiding as private members. Second, no paradigm has a truly unreplicable feature. You could reproduce this all in BASIC if you really wanted to. The tricky bit is making sure all the features mesh well, and enable-and-encourage a useful style of programming with those features. That’s why it’s called a “paradigm”.

    I could recreate contracts in C, and I might be able to recreate subtype polymorphism in C, but I couldn’t create subtyped contracts a la Eiffel in C.

    all OOP programs can be translated into C with minimal effort

    No, they cannot.

    1. 4

      Agreed. The author seems awfully dismissive of that one little bugbear of software: maintenance.

      But almost all the important OOP features are merely syntactic sugar; all OOP programs can be translated into C with minimal effort.

      I’m not OOP’s biggest fan and didn’t even dislike the essay that much, but this line displays some staggering ignorance.

      1. 2

        No. they cannot.

        Sure they can, for a given understanding of “minimal”… if it runs on a machine then it can be written in C. The only real question is “with how much effort?”

        1. 5

          This is the kind of semantic hair-splitting that undermines the article’s argument.

          1. 1

            I’m not sure we read the same article … it’s a discourse about the specific meaning of “essential”; the argument is semantic hair-splitting.

      2. 6

        Indeed, no programming paradigm is essential. Worse, no programming paradigm can teach us anything about the nature of programming, because programming is independent of all paradigms. (This is the content of the Church-Turing thesis.)

        The author seems very fixated on having arguments, being upset, and listing off ways in which their industry practices are different from others’ industry practices.

        1. 2

          Worse, no programming paradigm can teach us anything about the nature of programming, because programming is independent of all paradigms.

          I would dispute this specific claim because there’s more to programming and the nature of programming than the specific mathematical formulation.

          Programming is, to paraphrase Sussman+Ableson, fundamentally about managing abstraction and complexity. There is much we can learn from the specific formulation and tools that computer language give us for interacting with those things. It’s why barely anyone uses COBOL or BASIC anymore.

        2. 2

          I don’t understand arguing against the notion that grouping functionality together according to abstractions that are understandable to human readers does not make sense. I don’t particularly care about the syntax for doing this in a particular language but OO is the neatest way I’ve seen, in my limited experience.

          Could other people show me some examples of how the same type of abstraction and organising is done in non-OO languages? Is the argument that you can achieve abstraction and code organisation well without needing OO to be a rigid part of your language, and actually you gain flexibility without it?

          This notion was <mindblown.gif> for me:

          But, a method is nothing more than a function that takes the object as a (hidden) parameter. Everything is syntactic sugar.

          1. 9

            Chapter 1 of “The Joy of Clojure” does a pretty good job of explaining why “you can achieve abstraction and code organisation well without needing OO to be a rigid part of your language, and actually you gain flexibility without it”.

            Can be read for free here, and doesn’t assume any prior knowledge of Clojure, nor does it really focus on teaching Clojure. It mainly lays the philosophical foundation for why a language organized around functions and immutable state can be just as powerful, if not more powerful, than a language organized classes, methods, and object-bound state.


            What’s also nice about Clojure is that it has tended to decompose every “unique” OO concept from Java into an equivalent (often bytecode-equivalent!), and more flexible, Clojure concept, and they can be adopted optionally and a-la-carte as needed. For example, interfaces become “protocols”, POJOs become “records”, method dispatch becomes “multimethods”.

            Even what you described as a “mind-blowing concept” is there: in Clojure, any Java object can be invoked using a functional syntax, for example obj.method(arg) literally becomes (.method obj arg), with no loss in generality, but a gain in composability!

            Less far afield, in Python, code is organized using modules, not classes, as the primary mechanism. As I wrote in my Python style guide:

            You should usually prefer functions to classes. Functions and modules are the basic units of code re-use in Python, and they are the most flexible form. Classes are an “upgrade path” for certain Python facilities, such as implementing containers, proxies, descriptors, type systems, and more. But usually, functions are a better option. Some might like the code organization benefits of grouping related functions together into classes. But this is a mistake. You should group related functions together into modules.

            1. 7

              I think ML modules are strictly better at this for three reasons: (1) they allow encapsulation over multiple types at once, (2) the allow definitions of values in unbounded ways as opposed to always being tied to one type/object, and (3) they have a specialized language for information sharing which allows for richer composition.

              To just give a brief idea of this, consider a key/value database interface (and it’s been a while, so I’m just going to pseudocode this ML)

              type KV_DATABASE = sig
                type connection_info
                type db
                type key
                type value
                connect : connection_info -> db
                close : db -> unit
                store : value * db -> key
                fetch : key * db -> value option

              This interface richly describes how 4 types interact. Particular instantiations can make certain parts public and certain parts private: for instance, you might want to publicize connection_info and value, but hide key and db. Using the information sharing language, you can build bigger systems which share private information such as the true nature of the db type and work together at once.

              Finally, Scala is a good playground here because it’s clear that Odersky was heavily inspired by ML modules (some of his earliest Scala examples clearly use Scala’s advanced type member features to attempt to achieve this sort of ML-style modularity while pretending to be compatible with Java-style OO). At the same time, you can clearly see how this style runs contrary to the Java-like OO style also available in that language. Ultimately, most people go with Java-style OO as it’s more familiar and works better with the majority of the ecosystem and thus ML-style modularity is quite rare in practice.

              The key distinguishing characteristic is: “does your object represent the type of interest itself, or does it represent the API?”. In other words, are you writing class Database or are you writing class KVDatabaseApi?

              1. 4

                Tel hit the nail on the head. The ‘notion [of] grouping functionality together according to abstractions that are understandable to human readers’ is really modularity. Object-orientation is just one way of achieving that, and from our best understanding today the fact that it’s the most popular way is mostly an accident of history (see Richard Feldman’s excellent talk on this, https://youtu.be/QyJZzq0v7Z4 ).

                Modularity predates OOP: see e.g. Parnas’ seminal paper ( https://blog.acolyer.org/2016/09/05/on-the-criteria-to-be-used-in-decomposing-systems-into-modules/ ). And of course one of the big breakthroughs in abstraction was the notion of ‘abstract data types’, discovered by Liskov & Zilles.: https://blog.acolyer.org/2016/10/20/programming-with-abstract-data-types/

              2. 2

                As I heard somewhere, “OOP is just a formalization of previously used methods”. The main OOP methods were used before the term OOP came into life. People just noticed that they go together nicely, and decided to make this way of programming formalized. You can do OOP in C. You could probably even figure out how to do OOP using assembly. Doing OOP in Haskel might feel like trying to run backwards, but you can do it. So called “OOP languages” came after OOP was being used, to solve the difficulties that arose by using existing languages for OOP.

                1. 1

                  Just about everything that was touted as an advantage of OO makes more sense when services or actors are considered the objects.

                  1. 1

                    I like fortran level of OOP: modules with no inheritance, but still with public/private fields.

                    1. 1

                      What I would like to argue against is the common belief that Object-Oriented Programming is the ‘true’ way of writing any software system.

                      Is this a common belief? How large is the possible audience? How does it intersect with those likely to read this? If this is the goal, I’m not the target audience. Perhaps 1 or 2 of my colleagues… who won’t be reading it…

                      1. 1

                        I think I agree with the article overall there. Though not necessarily with the way it argues about it.

                        It’s weird to see subtype polymorphism and parametric polymorphism on same line there because the latter is easily implemented in a way that you can’t break the contracts that it represents.

                        In Python I don’t use inheritance for anything anymore. There’s always some better&easier to understand way to represent the same thing, and it appears when you don’t try to wrap it into OOP.

                        There’s really a good reason why ORM didn’t took over RDBMS. That has nothing to do with trying to apply OOP into a wrong domain. OOP just sucks. Algebraic and relational modeling works better and is easier for people to understand. cal.color = red is just an assumption of how data is accessed/created/scrubbed in comparison to color(car,red).