Settings

Theme

A Healthy Hatred of OOP, or the principles of my message-driven framework

bythehilt.com

87 points by rlt3 10 years ago · 97 comments

Reader

jasode 10 years ago

Your essay is arguing against a strawman of what "good" OOP is supposed to be. Your examples...

>Objects just aren't supposed to be reaching into each other with 'getters' and 'setters' and messing with information.

The getX() and setX() is an anti-pattern of good OOP.

>Instead of using objects for compartmentalizing functionality, they were just used as a holding pen for loosely related functions.

No, good OOP has class/object with both private state and associated functions combined to provide a public interface for clients to use.

(Although Java & C# (unlike C++) may have muddled this aspect because their language specification does not allow "free" functions to live in a plain namespace. Therefore, programmers are forced to use the "class{}" keyword with static functions as a workaround. Maybe that's where your "holding pen" characterization came from?)

>A traditional OOP approach uses shadowy architecture to remove the responsibility of an object,

No, good OOP tries to push responsibility into classes/objects so they can act as independent agents with minimal coupling to the outer context they sit in.

I'm guessing your comments are based on seeing a lot of poor practices masquerading as OOP which affects what you think OOP actually is. Unfortunately, it's like trying to argue against Javascript because of overuse of "eval()" or arguing the flaws of Haskell because variable names are often 1 character long.

There are definitely problems with OOP but they are not the bullet points you mentioned.

  • rlt3OP 10 years ago

    >I'm guessing your comments are based on seeing a lot of poor practices masquerading as OOP which affects what you think OOP actually is

    I personally feel that the current OOP model eventually devolves into the bullet points you listed given enough complexity.

    One reason why I think this occurs is that there is no concept of a 'message' in OOP, only methods or functions of a class. There's explicit coupling even when calling a method with no arguments because you know the method is valid for that object.

    Contrast this with the example of the 'listener' in the room. A speaker broadcasts his message but the independent agents ultimately decide what to do with that message.

    The OOP approach calls "object->listen" on each listener. My approach simply broadcasts the message and lets the objects determine how to handle it themselves.

    • vidarh 10 years ago

      > One reason why I think this occurs is that there is no concept of a 'message' in OOP, only methods or functions of a class. There's explicit coupling even when calling a method with no arguments because you know the method is valid for that object.

      This is specific to early-binding languages like C++, Java etc. Look at Smalltalk or Ruby, and this is not true in the general case. E.g. Ruby ORM's tend to dynamically create classes and methods at runtime based on analyzing the database schema of the database you connect to. You literally won't know if a given method exists until you've connected to the database. Even then, there are no guarantees - depending on framework it may e.g. let your call hit "method_missing" first time (or every time) and optionally then define a method (or it may continue to handle it via method_missing, but defining a method can be much faster, depending on situation)

      > My approach simply broadcasts the message and lets the objects determine how to handle it themselves.

      So OOP the way Alan Kay describes it, in other words.

    • pmontra 10 years ago

      Not all actor based languages can broadcast messages to e every actor. Example: Erlang sends messages to a given process. To broadcast to many processes you must know the pids of all of them. Or send to a "bus" process that knows the pids of every one else. Performance bonus (maybe) if the bus knows which process will be interested in a given message. Not much different than having a central registry of objects acting as a bus and dispatching method calls. Furthermore you can have tight coupling with message passing too.

    • jasode 10 years ago

      >One reason why I think this occurs is that there is no concept of a 'message' in OOP, only methods or functions of a class.

      If you mean there is no formal/explicit OOP syntax in C++/C#/Java etc for a "message bus" or "queue" for a decoupled publish/subscribe type thing, you're right. Yes, Golang/Erlang have that concept a little more "baked" into the language.

      But that's still orthogonal to the supposed OOP flaws you brought up.

      The C++/C#/Java approach to the missing "message" functionality would be either to create a class with a managed buffer to "hold messages" for other classes to write or read from... or use a library that interfaces with an external messaging bus.

      • rlt3OP 10 years ago

        >The approach to the missing "message" functionality would be either to create a class

        Yeah, I explicitly covered this. I don't feel like piling some 'controller' object on top of other objects necessarily accomplishes what I'm after.

        But it does work and I've used the pattern plenty.

  • atonparker 10 years ago

    It seems to me like you and the author agree about what good OOP should be (encapsulated state, message passing), except they argue that "traditional" OOP is not useful, and you see Traditional OOP as Good OOP. In fact, "good" is not used a single time in the article so I don't see how they could be constructing a strawman against it. I'm guessing the author is using "traditional" in the sense of what is traditionally taught, which in my experience was closer to Java beans and FactoryFactory classes. In other words, a terrible misinterpretation of Alan Kay's ideas.

    If you actually look at the framework they are presenting, it pushes the developer towards many of the "good OOP" points you made. So I'm not sure exactly what you're arguing here.

    • jasode 10 years ago

      >, and you see Traditional OOP as Good OOP.

      No, my comments don't agree with that.

      In fact, I tried to point out that his "traditional OOP" examples are incorrect OOP and therefore, a straw man to be arguing against.

      • abiox 10 years ago

        the swell thing about "OOP" is how ill-defined and vague the notion can be. just like "correct OOP" and "incorrect OOP".

        as a consequence, discussions can go back and forth, frequently resulting in little but gymnastic displays of equivocation and red-herrings. when the dust settles, surprisingly little communication has occurred.

        • mpweiher 10 years ago

          "OOP to me means only messaging, local retention and protection and

          hiding of state-process, and extreme late-binding of all things. It

          can be done in Smalltalk and in LISP. There are possibly other

          systems in which this is possible, but I'm not aware of them."

          http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay...

          • kazagistar 10 years ago

            That is not the definition of OOP the author is using. He made it clear what he meant by OOP; a paradigm seen often in production systems. Productive discussions start by accepting given definitions and arguing against the resulting points, not by arguing that the definitions are wrong because they don't match the exact form defined by someone somewhere.

            • mpweiher 10 years ago

              No, the premises always need to be examined, not accepted at face value.

              If the author is using a wrong definition as a starting point, the rest of the argument is largely pointless...or must be explicitly marked as a hypothetical/counterfactual.

              "I define the earth as being an infinite flat plane, from this it follows [for the real world] that..."

              Well, no, the earth is not an infinite plane, even if it kinda looks that way, was long believed to be that (maybe minus the infinite) and apparently there still are people who believe that.

              • kazagistar 10 years ago

                There is a difference between definition and assumption. An assumption says that something about the world is true. A definition just says what meaning you will intend by a word in the current scope.

                When you define OOP, you aren't saying anything about the real world, just stuff about the words you will be using within the current context.

      • _pmf_ 10 years ago

        > In fact, I tried to point out that his "traditional OOP" examples are incorrect OOP and therefore, a straw man to be arguing against.

        You successfully replaced his straw man by your true Scotsman.

        • jasode 10 years ago

          >your true Scotsman.

          I don't think "OOP" is an unreachable shared understanding such as the "No True Scotsman" applied to debated concepts like "communism".

          Despite the different vocabulary and emphasis of Alan Kay (Smalltalk) and Joe Armstrong (Erlang) about OOP, there is still a commonality of understanding there. The OOP concepts expressed in Objective-C, Borland Delphi, and other GUI toolkits share that understanding of encapsulated state with message passing (methods) via a coherent "public interface".

          The author was not arguing against that "shared understanding" of correct OOP. Instead, he highlighted bad coding practices (albeit very common ones), then labeled it as "traditional OOP".

          Yes, there is a ton of misunderstood and misapplied programming practices that others label as "OOP". That's the fault of the people doing the mislabeling and not the fault of OOP.

    • rlt3OP 10 years ago

      >I'm guessing the author is using "traditional" in the sense of what is traditionally taught

      This is correct and it's my mistake for not making this more clear.

    • collyw 10 years ago

      Seems that OOP is going the same way as Agile, and no one can come up with a consistent definition of what it is these days. Encapsulated state and message passing are not exclusive to the OOP paradigm are they?

    • stcredzero 10 years ago

      tl;dr -- Alan Kay emphasized the message passing nature of method dispatch in Smalltalk.

      A traditional OOP approach would have much of the functionality taken out of the player objects, using them simply to hold state.

      Sounds like C structures. Back in the day, we were always urging and cajoling programmers to stop thinking this way and think more in terms of Objects that knew how to do things in response to messages.

  • Tloewald 10 years ago

    In a sense the OP is making a point about which paths are paved in most OOP languages. That said, one of the problems I often see in user interfaces is "runaway metaphors". The "objects" and "messages" in question are _metaphors_ and it's important not to let a concept be taken hostage by the metaphors used to describe it.

    The main reason controllers exist isn't (or shouldn't be) because of a failure of OOP as a concept, but because of efficiency or complexity. Going back to the baseball example, while it might make intuitive sense for the player to send a "running to first" message, simulating a team's reaction to that event by having player objects communicate purely by messages is horribly complex, whereas a fairly decent simulation can be quickly created by "cheating" with a team controller object (or game controller or whatever).

    Even in a "pure" implementation, objects will want to examine each other ("how fast can that player run? Where is she right now? Now? Now? Where's the ball? Who has it? How good an arm do they have?")

    If anything, the baseball metaphor shows how complex things can get, and quickly reveals cases where almost any programmer would choose to violate encapsulation to make things work.

    • Retric 10 years ago

      how fast can that player run? Is asking about internal state. When can you get to X is not.

      The internal vs. external separation can often greatly simplify things. A player does not care where another players feet are they care where the best place to toss the ball is.

      PS: In an actual game there is a lot of communication going on. You don't want to throw a ball at someone looking in the wrong direction. So, at some level you're stuck dealing with innate complexity.

      • Tloewald 10 years ago

        Of course there's innate complexity, but pursuing encapsulation for its own sake adds complexity you don't need (just like using functional programming techniques for intrinsically non-functional use-cases adds complexity for no good reason).

        Again, "messages", "objects", etc. -- these are metaphors. They should be abandoned as soon as they stop being helpful.

        • Retric 10 years ago

          Generally, if you don't want encapsulation then your not dealing with an independent object. You could write a game using 2 objects or 2,000, but building complex systems without partitioning becomes incredibly difficult. At the core Objects are a very basic abstraction. It can be as basic as Simulation <-> Rendering, but it's hard to point to a complex system and say this really is best represented by a big ball of mud.

          So, sure not everything should be an object. But, saying nothing should be is a much higher hurdle than that.

          • Tloewald 10 years ago

            Of course, but this guy is saying nothing shouldn't be, which is an even higher hurdle.

  • smt88 10 years ago

    I think your comment highlights my biggest problem with OOP: no one agrees on what it is or how to organize it. The amount of mental energy I used to spend on exactly how things should be separated into objects and how those objects interacted was astronomical.

  • anexprogrammer 10 years ago

    You indirectly put your finger on the real problem with OOP, and that's that a lot of people using it in the wild are frankly not very good at it. Bad object design, not seeing what should be objects in the first place.

    I always felt that people who had never used C before C++ or Java, nor any other procedural language, aside from some scripting tended to some of the messiest OO. Seemed they'd want to create a sea of objects and patterns even when something simple was staring them in the face.

    OO is harder to teach, and clearly harder to understand. That's the top and bottom of most issues with it.

    • kazagistar 10 years ago

      > OO is harder to teach, and clearly harder to understand

      That is a pretty damning judgement of OOP. It seems to me the whole point of a paradigm should be to improve understandability. If, in practice, it makes it worse, then it is a failed paradigm.

      • smadge 10 years ago

        If you give someone a gun, they might shoot themselves. If you give someone a table saw, they might cut off their hand. If you teach someone objected oriented programming, they might write a unmaintainable ball of mud.

  • kazinator 10 years ago

    Moreover, getters and setters can be readily modeled with messages.

    That messages and (at least single dispatch) methods are identical was settled decades ago.

    (Has someone worked out a multiple dispatch OOP based on message passing?)

    • vidarh 10 years ago

      The conceptual difference between messages and methods to me is that messages implies that it is the object itself that is the arbiter of whether or not it can handle a specific call, and the decision may depend on factors not knowable before the call. While "method" implies to me that it is something that may be applied to the object by an external actor.

      E.g. if I do "foo.bar()" in C++, the compiler will simply not compile the code if "bar" is not already defined on the class "foo" is declared as. The object at runtime has no influence on the dispatch.

      In Ruby, on the other hand (as well as Smalltalk and other languages with late binding and message passing), regardless of implementation details, whether or not "bar" is not defined when the code is parsed is irrelevant. You can in the general case not know before reaching the call-site whether or not "bar" is defined, and even if it is not, it is not up to the interpreter to throw an error if e.g. a method_missing is defined, and you can't in the general case determine in advance whether or not there will be a method_missing defined when you get to the call site. The object can decide to process different messages depending on the time of day if it pleases.

      See also the Alan Kay quote elsewhere in this thread - especially the part about late binding.

      You can achieve this with e.g. vtable based dispatch (fill in "missing" slots with thunks that loads a symbol and calls method_missing, and fill in the "method_missing" slot with a generic one that raises an exception), so this can still lead to similar implementations. It's a different way of looking at things, coupled with the dynamism of very late binding.

      • kazinator 10 years ago

        > if I do "foo.bar()" in C++, the compiler will simply not compile the code if "bar" is not already defined on the class "foo" is declared as

        In a more dynamic language, in fact "foo.bar()" may be equivalent of asking foo whether it understands how to bar, and if so, then please do it. If foo doesn't understand, there could be some mechanism for handling that, like a catch-all function that can be defined that gets invoked.

        Likewise, we could also have a static language with message passing OOP in which the same check is implemented. The classes declare statically which messages they understand and the compiler checks that.

        Quite simply, "late binding" != "message passing". There can be late binding of messages, and late binding of function calls.

        There is no real conceptual difference between single dispatch and (synchronous) message passing.

        What is Unix ioctl? Message passing or function call?

    • KirinDave 10 years ago

      > That messages and (at least single dispatch) methods are identical was settled decades ago.

      This has been modeled out from message passing and procedural code semi-formally, with the first discussion (that named the duality) being available here: https://cseweb.ucsd.edu/classes/wi08/cse221/papers/lauer78.p...

      And it's fine for multiple dispatch as well, btw. Higher kinded types reward everyone equally here.

  • incepted 10 years ago

    Good points except saying that getters and setters are an anti-pattern of OOP. Actually, you contradict this a few lines blow:

    > No, good OOP has class/object with both private state

    If a class has state, you have to be able to read that state or it's useless.

    It's a good practice overall to tell classes what to do but eventually, you need to get information from them. That's where getters come into play.

    • jasode 10 years ago

      >If a class has state, you have to be able to read that state or it's useless. ... That's where getters come into play.

      No, having a bunch of getABC(), getXYZ(), getEtc() is a code smell.

      If the class has many getters()+setters() or has the equivalent of many public data members, it means that related actions requiring those variables are happening outside of the class/object instead of inside the class. The more getters()/setters() made available means the more the programmer is treating the class as a "dumb struct{}" with exposed members instead of a "smart agent" with knobs & levers to direct a hidden machine. The "knobs & levers" should be higher-level public methods that are not gets()+sets().

      For example, let's say we have a TextBuffer object:

      With get()/set() mentality:

        TextBuffer.setLinecount(0); // reset counter to 0
        for() {
          TextBuffer.getNextLine();
          n=n+1;
        }
        TextBuffer.setLinecount(n);
      
      With a public method to make the object smarter about itself:

        TextBuffer.CountLines();
      
      The method CountLines() replaces gets()/sets() and makes the object more "black box". The "for(){}" loop would be inside the object.

      Making objects "smarter about themselves" is a hallmark of good OOP. Less exposed getters() is less coupling and less pollution of classes' internals to the outside world. Refactoring/reducing gets()/sets() means unifying those outside actions acting on object's internals into a higher-level method interface.

      I'm not saying all gets() can be eliminated. But the Java practice of having 20 private member variables mirrored by 20 public gets()/sets() is not what OOP is about. It's actually about as opposite from OOP as you can get!

      • matwood 10 years ago

        > I'm not saying all gets() can be eliminated. But the Java practice of having 20 private member variables mirrored by 20 public gets()/sets() is not what OOP is about. It's actually about as opposite to OOP is you can get!

        Maybe people are just confusing different sides of the same concept. There are smart objects as you mention and dumb data holders that are used to pass 'messages' around. The classic anemic data model, with objects that operate on said data.

      • incepted 10 years ago

        You don't seem to realize it but your countLines() method is a getter.

        At the end of the day, you need to get values from your class, otherwise, they are useless (and they do side effects).

        • jasode 10 years ago

          >At the end of the day, you need to get values from your class,

          Yes, you eventually have to <scarequote>"get"</scarequote> values from the class but you don't literally have to mindlessly create a one-to-one set of "get()" for every private member variable.

          The author's example and my response to it were talking about a literal thin wrapper of public getX() for a private int x. This practice deceptively looks like OOP (I "hid" that private member with a public method) but it's not really OOP.

          Instead of gets() & sets(), the programmer should find the higher level concepts to turn into higher-level methods. This way, the gets()/sets() is kept to a bare minimum.

  • patrickmay 10 years ago

    > The getX() and setX() is an anti-pattern of good OOP.

    This needs to be tattooed in reverse on many developers foreheads so it's the first thing they read when brushing their teeth in the morning.

    • UK-AL 10 years ago

      Problem is developers take that as an excuse to make state public, which is even worse.

      • kasey_junk 10 years ago

        It doesn't matter whether you make the state public via a getter or via variables (modulo some compiler specific reasons to use accessors).

        If your design is allowing some external actor to work with multiple parts of the state of a behavior driven object (ie not a record) accessors are not going to help you, you've still exposed the state.

        • UK-AL 10 years ago

          Completely agree.

          But at least with getters/setters you can intercept calls before they modify state.

          But you should design so you don't need this in the first place.

  • KirinDave 10 years ago

    "Good" OOP and "bad" OOP. There's just no difference. And quite frankly, if the only difference between their "getX" and a symmetrical message passing pattern that retrieves a copy of an attribute is the implementation details then... what?

    So much of "Good OO" seems to be prescribing people's mental models and not their actual practices. Seems somewhat odd to me, since most of the models are indistinguishable from one another in practice.

  • jack9 10 years ago

    > No, good OOP has class/object with both private state and associated functions combined to provide a public interface for clients to use.

    I don't believe there's evidence of this. Inteface scoping (e.g. "private/protected/public") is a relatively recent invention to protect against programmers who "don't know what they are doing". Adequate documentation is a superior tactic since that's a cursory best practice.

  • collyw 10 years ago

    I am glad I work in a mixed metaphor language. Choose the best bits when appropriate instead of arguing what is proper OOP or not.

    • jasode 10 years ago

      > instead of arguing what is proper OOP or not.

      Every programming paradigm and every programming language suffers the distinction of what is "proper" and "improper".

      There's proper functional programming and improper functional programming. For example, it's possible to write bad code of passing GodUniverseState records to "functions" that the Haskell/Ocaml compiles without error. However, that's not "proper" functional programming. It's just messy global state masquerading as a functional program.

      There's proper SQL usage and improper usage. For example, writing a stored procedure to loop through one table with a cursor, and then looking up a column value in another target table is "improper SQL". SQL has built in "joins" to do it correctly (and also performs faster as a bonus).

      Even Python has a category of "not Pythonic".

  • spriggan3 10 years ago

    > The getX() and setX() is an anti-pattern of good OOP.

    No it isn't, it provides encapsulation, which the most important aspect of OOP.

    I agree with the rest.

    • jasode 10 years ago

      >No it isn't, it provides encapsulation,

      The extensive use of getters()/setters() is a common misunderstanding of "encapsulation". It's an example of following the "letter of the law but not the spirit of the law".

      Let's separate the idea of "encapsulation" into 2 categories:

      (1) syntax encapsulation: private int x; public getX(); public SetX(); // letter of the law

      (2) conceptual/semantic encapsulation: Object.DoSomething() that works on x internally // spirit of the law

      It's the idea presented in (2) that follows the ideals of OOP design and helps reduce cognitive load. The common coding practice of (1) doesn't really provide "encapsulation" that helps make large scale programs more understandable. I also think (1) was exacerbated by codegen tools such as ORMs and GUI data binding frameworks. Therefore, inexperienced programmers thought that having a ton of gets()/sets() in their own manually handcrafted classes was "correct OOP".

      • Terr_ 10 years ago

        Or to put it another way, encapsulation of state versus encapsulation of logic.

    • jandrese 10 years ago

      It can very easily break the encapsulation though. Now external processes are dependent on direct access to the internal state of your object, and if the object is refactored in the future you need to reprogram those getters and setters to return something that is still correct but may not represent the internal state of the object at all and may in fact be complex now.

      An example of where this can all go wrong is if you have a TCP object that opens a connection to a remote server and then lets you read and write the socket. Someone decides that they need to find out what IP address the object used when it connected and create a get_ipaddr() method that returns a s_addr type. But then the TCP object is updated to support IPv6 and now the author needs to figure out how to return a V6 IP address to external methods that only expect V4.

      The proper way to implement it might have been to move whatever logic was examining the IP address into the TCP object itself. Of course this is how you end up with horrendously complex objects with hundreds of methods all used exactly once somewhere in the code or exactly once in the code of some other project.

      • spriggan3 10 years ago

        > An example of where this can all go wrong is if you have a TCP object that opens a connection to a remote server and then lets you read and write the socket. Someone decides that they need to find out what IP address the object used when it connected and create a get_ipaddr() method that returns a s_addr type. But then the TCP object is updated to support IPv6 and now the author needs to figure out how to return a V6 IP address to external methods that only expect V4

        In that case you should use polymorphism. There is no reason why the consumer of the address returning the IP should know whether get_ipaddr returns an IPV4 or an IPV6 directly.

    • ThrustVectoring 10 years ago

      Getters and setters are an anti-pattern that works around a specific deficit in a programming language. In Python, if you want to refactor an object so that `foo.bar = baz` does something other than blindly set foo's bar to baz, you can. In Java, you can't, which is why setting foo's bar to baz is done with `foo.setBar(baz)`.

barrkel 10 years ago

The OOP referred to in this article is certainly a straw man, but the alternative suggested has problems too.

Teams that work well act almost like they're mind-reading one another. High quality orchestration of disparate parts is in tension with encapsulation.

Actor-based programming is highly concurrent but in my experience it's harder to reason about as it scales up. Emergent behaviour of interactions between hidden states is sometimes the goal, and sometimes an unwanted side-effect. Network protocols are tricky to get right for a reason; splitting everything out into a shared-nothing message-passing architecture isn't a panacea.

I lean more towards explicit but immutable data structures, and referentially transparent functions over those data structures. In this world, parallelism can increase performance without observable concurrency. Concurrency is the root of non-determinism; non-determinism should be avoided unless it's inherent to the problem at hand.

OOP is a middle ground in this world, but it's ill-defined. Depending on style, it can be stateful and imperative, functional or message-oriented. OOP is not an absolute bad; with effort, it can be massaged, or herded, into working patterns. But it's certainly not a universal optimum.

carsongross 10 years ago

A traditional OOP approach would have much of the functionality taken out of the player objects, using them simply to hold state.

I don't agree with that characterization. The author certainly has a point that, in some languages in particular, like java, there tend to be massive over-decomposition of problems into reams of factories, controllers, controller factories and controller factory manager factories, but that isn't OOP, that's due to cultural and syntactic issues with those languages. (I know, I know, No True Scotsman.)

In the Rails world, which is a non-trivial component of the broader OOP software world, there is a saying: "Fat Model, Skinny Controller" which is much more in the spirit of what the author is advocating, despite remaining OOP.

Again, this isn't to deny the authors general point, but I don't believe it is bound to OOP, so much as it is to a certain style of OOP coding that arose from early (java in particular) over-engineering and excessive decomposition.

ninjakeyboard 10 years ago

I made up the term 'object-oriented', and I can tell you I didn't have C++ in mind

-- Alan Kay, OOPSLA '97

rdtsc 10 years ago

Joe Armstrong's thoughts on how Erlang is more OO than OO languages:

http://erlang.org/pipermail/erlang-questions/2009-November/0...

Joe likes to be funny, so don't get upset and confrontational about it.

The central idea is this I think:

---

I now believe the following to be central to the notion of OO.

      - Isolated concurrent things
      - Communication through message passing
      - Polymorphism
All the other stuff (inheritance, private/public methods, ....) has nothing to do with OO.

---

  • incepted 10 years ago

    FYI, Armstrong thinks that OO sucks [1] so it's weird to see him claim his language is a better OOP language than others.

    [1] http://harmful.cat-v.org/software/OO_programming/why_oo_suck...

    • rdtsc 10 years ago

      ... "Joe likes to be funny" ...

      Besides this idea of taking a label away from something you don't like is also a good strategy in general. He obviously doesn't think Erlang should do multiple inheritance. He just points out languages that have been calling themselves OO these years have been impostors.

      Also not sure if I mentioned, Joe like to make witty jokes. So don't take it too seriously.

  • zzzcpan 10 years ago

    Don't take it seriously. Joe actually admitted, that they only called Erlang OOish because of the OO hype, but Erlang is not an OO language in any way, of course.

    • Diederich 10 years ago

      I would gently submit to you that Erlang is pretty close to the definition of 'Object Oriented' as given by the guy who created that phrase.

      The commonly held definition of OO has drifted far from that ideal over the years.

      • rdtsc 10 years ago

        It is. But at this point it is rather tongue-in-cheek. I certainly wouldn't want Erlang to all of the sudden be called Object Oriented.

markbnj 10 years ago

>> When I started learning C++ I was shocked. Instead of using objects for compartmentalizing functionality, they were just used as a holding pen for loosely related functions. Instead of communicating between themselves, objects were operated on by some bigger parent object. I found it absurd and fought it for a long time.

This has nothing whatsoever to do with C++. It's like blaming a microwave oven because your kid put a ball of tin foil in it.

C++ is a great language when you are developing big compiled programs and need strong metaphors for decoupling and modularity. Most developers today work on distributed systems where the individual cooperating pieces that they write are much smaller. Your 1000 line HTTP handler in python won't benefit much from strong static type checking, but the linux kernel does, and so do a lot of the infrastructure components we all take for granted every day.

  • wtetzner 10 years ago

    The Linux kernel is written in C, not C++. C has static typing, but it is definitely not strong static typing.

    • markbnj 10 years ago

      Yeah I did not mean to imply that the kernel was written in C++. As to whether C is "strongly typed" or not that is a matter on which we can disagree, as there is no agreed-upon definition of what that means. In my view it certainly falls on the strongly-typed side of the line when compared to the languages most developers use today. The point of my response is that OO methods as embodied in C++ were a response to the growing complexity of compiled programs back when it was developed, and those principles definitely helped developers, including myself, get a handle on that complexity.

paulddraper 10 years ago

One of the more ironic titles I've seen.

Alan Kay (progenitor of Smalltalk and OOP) has said on various occasions that it should have been called message-oriented programming, rather than object-oriented.

"I'm sorry that I long ago coined the term 'objects' for this topic because it gets many people to focus on the lesser idea. The big idea is 'messaging'"

http://lists.squeakfoundation.org/pipermail/squeak-dev/1998-...

nbevans 10 years ago

The same thing happened with REST, TDD and Microservices, etc. The term gets hijacked by people that are less than skilled at executing it. And unfortunately there are more unskilled than skilled people in software; so usually the hijacked term wins the contest. It then takes decades of the "original guy" sending out a BBS message / IRC message / vBulletin post / Blog post / Tweet / HN comment / etc to try to correct people's understanding by saying "actually, that's not canon!".

copx 10 years ago

Comment on the code:

As a Lua aficionado I hate to see stuff like this:

  Ball = {}
  Ball.__index = Ball

  function Ball.new (x, y)
    local table = {}
    setmetatable(table, Ball)
    table.x = x
    table.y = y
    return table
  end
Explicit setmetatable() call and manual __index setting? You can automate this and hide all the metatable magic = less code to write, less potential for bugs.

E.g. in my own Lua object system the above would be:

  Ball = Class()

  function Ball:Properties(x, y)
    return { x = x, y = y }
  end
KirinDave 10 years ago

I think that we suffer from a paucity of precise language around OOP. Everything is OOP, everything is what Kay created, etc.

But that's clearly not the case, and so people have these radically divergent systems of programming within the framework of "object orientation".

My read of this article and it is very message-passing OO to me. Its broadcast mechanism is interesting, for sure. But it reads a lot like Erlang's supervision tree without all that troublesome thinking about a network.

But it's approach is still very "OO".

daxfohl 10 years ago

The downside of message passing is debugging. No call stack so you can't trace things back to their source.

  • SlipperySlope 10 years ago

    An agent framework I built for my AI research has exactly that.

    I use an additional message parameter, automatically inserted and maintained by the framework, which is a list of the messages (FIPA style operation + parameters) from the originating agent forwards to the point of debugging. This gets voluminous and is gated by debug levels.

    • Diederich 10 years ago

      Same here. The framework I've been building over and over for various companies for the past 20 years has extensive debugging capabilities. With the right 'messages all the way down' mindset, it gets extremely powerful.

  • vidarh 10 years ago

    Message passing in the OOP sense does not imply there's no call stack. Whether or not there's a call stack is an implementation detail.

    The same holds true if you actually pass async messages on a bus - nothing stops you from attaching call details to the message. In fact, we have one very prominent async messaging system that does exactly that: E-mail (via "Received:" headers). (And yes, I've used e-mail as a message bus for applications before - Qmail worked great for that)

  • mpweiher 10 years ago

    Maybe we need better tools?

    "Causeway, an open source distributed debugger written in E, lets you browse the causal graph of events in a distributed computation."

    http://www.erights.org/elang/tools/causeway/index.html

  • kazinator 10 years ago

    That's a big down side of a framework for asynchronous message passing (object-oriented or not). E.g. "Flow based programming".

    Message passing OOP doesn't necessarily imply that type of message passing. That is to say, the "send" call doesn't have to return until the target object has processed the message.

    • onnoonno 10 years ago

      In a way, message passing using the usual way, methods, means TWO messages are passed: The parameters and the return value.

      I think that obscures the better parts of the OOP view quite a bit.

      • kazinator 10 years ago

        Also, method calls (that return) are really two calls, in a way: the call which passes the arguments along with a continuation, and then the call to the continuation which returns the value. :)

  • koder2016 10 years ago

    If the framework is factored well, then you can plug-in a synchronous single-threaded message delivery when debugging.

amelius 10 years ago

The only good thing that OOP brings to the table is, in my opinion, access control.

  • kevinavery 10 years ago

    Also referred to in this context as encapsulation. OOP provides a method of information hiding that allows implementation details to be changed later without changing the public API.

    • abiox 10 years ago

      one downside being that you risk creating obscured islands of mutable state, complecting engineering efforts.

      • kevinavery 10 years ago

        I view that more as a risk of using mutable state, not OOP. Regardless, I'd rather have the mutable state contained in as limited a scope as possible.

sbov 10 years ago

Isn't this basically event driven programming?

koder2016 10 years ago

> Objects just aren't supposed to be reaching into each other with 'getters' and 'setters' and messing with information.

In pure Actor Model adding two numbers would probably involve 2+ actors, yet Erlang is not doing this for some reason... I guess on a lower level hardcoding messages makes complete practical sense.

lucb1e 10 years ago

Some meta feedback on the article: this font is too big to comfortably read on mobile, fitting about five to seven words on a line (the typically recommended line length is about 14 words).

qaq 10 years ago

How does this make fp? If we fill fp with plugs for 1 man projects with 1 watcher we'd have 1000s of entries a day.

andrewmcwatters 10 years ago

The less actual code I see in articles like this, and the more abstraction I read about, the less I take the concept seriously.

In fact, all of this seems like bullshit to me. The actual code inside of the repo is, well, object-oriented. How I interpret this is that the author seems to have no idea what they're even talking about, and that they write more about code than they write code itself.

Show me what you mean, don't just talk about it.

  • rlt3OP 10 years ago

    I should have a tutorial out very soon. The documentation is not yet complete but does have a few examples.

    Also, of course it's object-oriented. The article is titled a "healthy" hatred for a reason.

    • orillian 10 years ago

      I just have one smallish question. Is the need to bench then add an actor the only way you "allow" transfer of children between parent actors?

      In similar systems that I have constructed in the past, I have used a number of methods for passing actors in different states.

      Pass a fully instantiated actor via a transfer process. Nothing changes for the actor, beyond reassigning parentage.

      Pass a cleaned actor via a similar process to the bench and add process. This was used to allow an actor to be reduced to a resting state as it were. In most cases you could think of it as a resurrection method that allowed discarded actors to be reinstated with only specified base properties in place.

      Anyway, I don't use Lua at all, but I like these type of actor messaging models. I look forward to reading through the rest of your documentation once it's done.

      O.

      • rlt3OP 10 years ago

        >Is the need to bench then add an actor the only way you "allow" transfer of children between parent actors?

        Currently, yes. Since this is sort of an entity component system and that actors can always create more children anytime they want, I suppose I just always assumed that actors could be "spun-up" with any sort of functionality and then deleted when not used.

        Benching/Joining an actor is more for handling errors at runtime or for debugging ("If I temporarily remove this actor will it solve my issue?").

CyberDildonics 10 years ago

TLDR: Terrible programming practices end up putting blame on labels and languages.

andrewvijay 10 years ago

The more I read about functional programming the more I question why are things this hard in traditional oops. If so many people have been doing oops for so many years then it must have something that is easy to pick up or something that is easier to work with. But after doing some functional programming the number of lines are painfully less and the code is easier to understand. I was thinking may be I was giving too much credit to FP but I was not it's simply just the way things are. But why has FN been used only as an academic tool and not as a goto programming paradigm? Can someone shed some light on this?

  • lostcolony 10 years ago

    Broad generalizations here, but from my understanding -

    Back in the dark ages, the performance difference between imperative code and functional code was too large for FP to gain much traction outside of academic circles.

    By the time the hardware was anywhere near reasonable, OO had become a thing. People missed some of the key points Alan Kay had, latching on to the one thing that was immediately understandable: objects could model the nouns of your problem domain. That popularity meant that the mainstream was focused on OO, rather than FP.

    I went through college in the late 2000s, at a well respected university, for computer science. I had classes devoted to OO(A/D/P); I had none devoted to FP. If you were exposed to it, it was via having to learn a Lisp in the AI class, or similar.

  • nv-vn 10 years ago

    Historically, mostly performance. Outside of academia, performance becomes an important factor in most programs. In the past, both slower computers and fewer optimizations made implementing the abstractions of functional programming ridiculously costly. Once it lost out to imperative programming, it only got harder to change the tide. Performance is now adequate but functional languages lack educational material and libraries as well as industry support.

Keyboard Shortcuts

j
Next item
k
Previous item
o / Enter
Open selected item
?
Show this help
Esc
Close modal / clear selection