Live data from Hacker News

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

bythehilt.com

41–50 of 98 posts

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

#41
post #4

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 c…

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.

>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!

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

#42
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.

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

#43
post #4

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 c…

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?)

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.

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

#44
post #9
post #4

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 c…

>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…

> 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.

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

#45
post #6

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

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.

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.

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

#46
post #4

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 c…

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 traditionall…

>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.

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

#47
post #6

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

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)

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

#48
post #32
post #15

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 (inheritan…

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.

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.

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

#49
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-...

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

#50
post #4

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 c…

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…

> 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.

Post reply on HN