Hacker News new | past | comments | ask | show | jobs | submit login
Message Oriented Programming (atomicobject.com)
101 points by micahalles on Nov 15, 2012 | hide | past | favorite | 62 comments



In the interests of rigor I'm going to propose a ranking system. A higher rank means more "Message Oriented".

Rank 1: Polymorphism. You can "send" a message to an object. You don't know or care exactly what the object does. Other than the polymorphism, the "message" behaves just like a function call. It will definitely be handled by your target object, and it will definitely return instantly with a response. The compiler might even be able to inline this function call.

As seen in: Pretty much every OOP language.

Rank 2: Messages as first-class values. It's possible to write a function that forwards all incoming messages to another object, based on some logic. The caller does not know what will happen to the message. However, the message can be expected to be handled instantly, and it may respond instantly (if it does have a response).

As seen in: Objective-C, Smalltalk

Rank 3: Asynchronous messaging. When sending an outgoing message, it might be placed in a queue and handled at a later date. The message does not return a result instantly, so agents must have some other mechanism (such as including a "reply to" address) to be able to talk back and forth. From the perspective of the caller, it's a bit like putting a message in a bottle and watching it drift off to sea.

As seen in: Erlang, message queueing libraries.


I'm going to be the token annoyingly overeager Go supporter and post that Go channels fit nicely into rank 3.


Scala with actors fit into rank 3 too.


That's nice and simple. I like it. "Message passing" means too many different things (though not as many as "object-oriented"). Distinctions are helpful.

One thing people usually understand as part of "message passing" is "no shared state". How/where do you fit that in?


> One thing people usually understand as part of "message passing" is "no shared state". How/where do you fit that in?

Good question, it seems like all definitions of message passing involve not sharing state. Even OOP emphasizes data hiding as a core practice.


But there's a huge difference between working in a model where you can do it (even if you're "not supposed to") and working in a model where it's impossible. I've been writing a Chrome extension, where the programming model is a #3 in your system — everything is async and shared-nothing — and boy do I notice the difference. Calls between two Chrome contexts are done by async message-passing using JSON, and this is like walking through mud in heavy boots compared to calling something in the same context (a normal function call). No doubt well-designed languages and libraries help to make it easier, but still. I suspect asynchronousness is responsible for more of the mental burden than shared-nothingness is (or, more precisely, serialize-everything-into-JSON-ness), but they're definitely both contributors. It's the latter that makes it impossible for me to pass a DOM element from one context to another, for example.

When "passing a message" is a heavier operation syntactically than "calling a function" is, one thinks of the two as being more fundamentally different than they really are. I find that interesting because it's superficial yet influential.

Do Erlang programmers think of function calls as a kind of message passing? or as totally different things? How far apart are the two, psychologically? Is sync vs. async the more fundamental distinction?


About Erlang and function calls: I tend to view them differently. For me, in Erlang code, function call is about 'here', while sending a message is about 'there'.

Syntactic difference is big, but neither function call nor message send are heavy:

    func({my, params, in, a tuple})
    proc ! {my, params, in, a tuple}
The difference is that function call returns something, message send just happens and we have no guarantee at all what is going to happen with the message.

We frequently write functions which send message and wait for reply for a certain amount of time, and then return this reply or error if no reply was sent.

So, in Erlang there is - I think - huge difference between functions and messages, but that is because it's functions are just that: functions.

The situation is quite different in Smalltalk, where you have no functions at all, only objects. Everything there already is a message being passed, and so the difference between asynchronous and synchronous message should be very minor. I don't know Smalltalk well enough, but I suspect there are libraries implementing async message passing in Smalltalk and that they are almost indistinguishable from normal Smalltalk code, if at all.


> Everything [in Smalltalk] already is a message being passed, and so the difference between asynchronous and synchronous message should be very minor

But this seems to confuse paulhodge's #2 and #3. Messages as first-class values don't give you asynchronous messaging for free. Or do you just mean that syntactically the async code would look like normal sync code? That's true of JS as well, of course, and it's a problem. Async vs. sync is a fundamental distinction for the programmer, and one wants help to keep track of what's going on. I suspect Erlang got it very right in having two lightweight but distinct notations for these two deeply distinct things. What other languages do that?

Edit: It occurred to me that you said something profound:

> For me, in Erlang code, function call is about 'here', while sending a message is about 'there'.

"Here" vs. "there" is a spatial distinction; "sync" vs. "async" is a temporal one. The temporal distinction is far harder to get one's (my) head around, perhaps because code itself is laid out spatially, so you constantly have to recreate its temporal model in your head when you read it, and that's taxing. It's far easier to think of code as divided up spatially. We build up a system by making repeated 'inner' vs 'outer' distinctions - i.e. modularity. That structure is static while the temporal structure is dynamic and unpredictable. To write good async code you have to get in the habit of thinking "who knows when". But you never have to think "who knows where". The code tells you where.

This makes me think that there is wisdom in Erlang's decision to identify the temporal distinction (sync vs. async) with a spatial one (inside a process vs. outside it) — thus guaranteeing a translation from the harder mental category to the easier one — and to provide distinct notations for there-and-async vs. here-and-sync, so you always know which is which. Total complexity seems greatly reduced this way compared to a model in which the two distinctions are orthogonal and can combine in arbitrary ways.

For Erlang to say that between objects (i.e. processes) things are async and pass messages, while within an object they are sync and call functions, is a major departure from the Smalltalkian "everything is the same everywhere" small-and-regular philosophy. I'm fond of small-and-regular designs, but sync vs. async is one of those distinctions that is so fundamental, it's folly not to have it in the core unless you intend to get away with pretending that everything is always synchronous.


There is one more aspect here: concurrent vs. sequential. You can have a system which is both asynchronous and sequential, like JavaScript and Twisted, and another which is concurrent, but somewhat sequential (with mutexes and such). Erlang has both asynchronous message passing and concurrent threads of control (without any locks) which, without the simplification it makes (there -> async, concurrent; here -> sync, sequential and no shared state at all) would be pure madness :))


So you're saying that the alternative to Erlang's simplification is not a four-way combination but an 8-way one. Yikes.


So would messages ala Laurent Bungion's (sp?) MVVM-Light Messaging system fall under 1,2, or 3? You send out a message from an object and then any object "registered" to receive these messages can pick them up and handle them as they wish... doing something, doing nothing.... returning a value or more likely not...


Can't most languages in (1) implement forwardable patterns that accomplish (2), or is there some underlying language features in Objective-C or Smalltalk that are superior in this case?


Sure, with enough boilerplate code you can do anything in anything. It's more of a categorization of what's the normal style, of what is already provided and encouraged.


In Objective-C, I can easily say "if anyone calls a method on me that I don't implement, sent it to this object instead". I can also say "if anyone calls a method on me that I don't implement, do (foo) instead".

C++, for example, has no equivalent language facility for these scenarios; in fact they're nonsensical since they would both fail to compile.

You could build a similar system for C++ by making every object inherit from some base class that has a method performMethod( method, params) and replace all C++ method calls with your modified calls; but you're building a facility from scratch that comes out-of-the-box on Objective-C.


I'm guessing that in these languages you don't need special argument types (or you can use the same code for any function)

There are several others that support this though... Python and JavaScript spring to mind.


Asynchronous messages can also return results instantly in the form of futures/promises, avoiding the need to program in a continuation passing style with "reply-to" addresses. Mark Miller's E language does this.


As with many things, the bias toward object-oriented programming (OOP) rather than message-oriented programming (MOP) reflects a tradeoff at implementation time. There is more to MOP than just the interfaces (OOP has that), it is also about methods for optimally scheduling message flows, preferably asynchronously or even out of order.

MOP has upfront costs that you do not have to pay using OOP if your software system remains reasonably small. Many software systems start out with the limited goals that suggest it would not be worth the effort to implement a MOP architecture. As an aside, this partly a reflection of the fact that our software tools for OOP are much better than our software tools for MOP. A good MOP implementation still requires rolling a lot of your own infrastructure components.

However, MOP architectures scale much better than OOP architectures if you need them to. The clarity of resource boundaries implicit in MOP architectures eliminate a lot of coordination and decouple nominal dependencies. Even if you start out building a MOP design on a single computer, where every core has its own process and set of resources, the design leap to putting those components on different hardware or different computers is relatively small. The interface is the same, only the latency changes, and there are many methods for making that abstraction efficiently scale this way. This is the reason large-scale parallel and distributed computing systems are all based on message-oriented architectures.


'MOP' has been my go-to paradigm for most of my professional career. I freely admit that I 'go there' too soon in some situations, but you are quite correct about the benefits.

Scalability is only one benefit. Testability is another. And my favorite, it's very easy and usually safe to do run-time hacks, as the need arises.

I am currently working on a wide-scale, multi-language MOP family of libraries that I hope will make this programming paradigm a lot more accessible.


hey, i'm playing with some MOP like systems on the side myself. I haven't figured out how to make the code language independent yet but have ideas. Most of it is mostly exploratory. If you are interested in a discussion, contact me. It would be cool to discuss witha like-minded engineer.


I think messaging (http://en.wikipedia.org/wiki/Message_passing) has always been an important aspect of OOP that was somehow "missed".

"OOP, defined in the purest sense, is implemented by sending messages to objects." - http://www.inf.ufsc.br/poo/smalltalk/ibm/tutorial/oop.html

For varying reasons, people focused on inheritance. In my opinion, inheritance is bad (at least the over-use of).


It wasn't just an important aspect, it was the aspect. I'm glad the author included the link to Alan Key's email message because it really brings home that fact.


This is exactly what Object-Oriented programming was supposed to be. Passing messages to objects that know how to respond to them, without you needing to know how they do it or them needing to know why you asked.


Yes, but it certainly was not what it became. I'm less impressed by one guy's stated goals forty years ago than what it actually became.

That's not a criticism of Alan Kay. It's an observation that his saying a thing a long time ago didn't and doesn't change what actually was created, and what OO is today is not message passing.

The very, very core of what we call OO today, the feature without which you can not call yourself OO, is the binding together of a structure with associated "methods" for operating on it into a single unit. It's a way of structuring programs (note I do not say "language"; C can be programmed in OO, for instance) that chooses the OO answer to the Expression Problem: http://c2.com/cgi/wiki?ExpressionProblem There's other frippery... there's a LOT of other frippery, actually, tons and tons and tons... but that's the core.

It is not message passing. And the attempt to map one to the other is pretty klunky and generally lossy in both directions, another sign they really aren't the same thing. Alan Kay's description of message passing, when read in English rather than Smalltalk, always sounded a lot more like Erlang than Smalltalk to me, but I observe that Smalltalk is what he in fact created as the manifestation of his ideas, not Erlang. I think we can't ignore that fact.


Yikes! The expression problem is a small deal and has been solved many different ways (I wrote a paper on this in 2001, I debated this point with Wadler in 2002, this is so old news). My favorite way today is to use traits and type members in Scala, but any language that supports open classes would be even more elegant. Also, its a non-issue in dynamically typed languages.

We are only arguing pedantically about what OOP "means," and everyone has their own definition. Useless. My own definition associates OOP with object thinking, the deconstruction of your problem into interacting objects, and then the use of plumbing in your language that help you realize this deconstruction in a solution. What that plumbing is can vary greatly and involves some combination of methods, messaging, classes, interfaces traits, prototypes, constraints, behaviors, reactions, reflexes, patterns (beta style), state encapsulation, etc...

I like the idea of MOP, its like focusing on one aspect of the plumbing and fixating around it; I could never write a program using messages alone in my domain (like I couldn't really write a compiler using actors!). MOP and OOP are not orthogonal, they are describe completely different granularity.


Yes, I know the expression problem is old news. So is OO. There are plenty of things coming out that move beyond it or beside it or incorporate it as a thing in the language rather than the thing the language is bent around, but that is still the core idea in OO.

And if you carefully read my post again, you'll see I didn't give a definition. I talked about the one element that I've seen that is common across all of them. I can name OO languages with no first-class support for inheritance, no classes, no interfaces, or any of the other things you name, but I can not name an OO language that does not have some first-class binding of a structure to the methods to operate on it, nor can I show you an OO program in a non-OO language that is missing that, because that's essentially a logical contradiction. That's the single core idea that is what OO is.

This dodges the "everybody has their own definition" problem entirely.

Message passing as a primary means of structuring your program and OO are incompatible. One's going to have to be meshed within the other. One's this fundamentally asynchronous, distributed way of programming, and one is an elaboration on structured programming. Someone's on top. You get the same thing between FP and OO; you can put OO in FP or you can put FP in OO (quite popular, Python/Ruby/etc. fit here), but one is going to have to be on top. They can't be peers, they have fundamentally different ideas about what is most important.


You just aren't trying hard enough. The first OO language (SketchPad '62) was constraint based (visual and based on prototypes). Then there was ThingLab (Borning, 78?). And for my own work, check out SuperGlue (ECOOP 2006, OOPSLA Onward! 2007). No methods to be seen...and still very OO.

Incompatible or orthogonal? Message passing is primarily an issue of software architecture (using Garland's definition) while OOP is more of an issue of linguistic abstraction.

OOFP is definitely possible, like say Moby or OCAML. The distinction between OOP and FP is hardly as black and white as you think.


With all due respect, I think you need to stop glancing over my posts and looking for things to pick at with all possible speed, and maybe spend a bit of time actually reading them, before you go jumping all over them any more. Your last paragraph in particular is pretty much proof positive you did not actually read the post you are replying to.


I did read your post, I was disagreeing with this:

> They can't be peers, they have fundamentally different ideas about what is most important.


For what it's worth, Sketchpad is described by wikipedia as a program and not a language, and moreso it "pointed the way forward" to OOP, in that Sketchpad included the concept of "master drawings" (read: classes) which could be instantiated into duplicates, such that when the master drawing changed, any previously instantiated duplicates would be changed accordingly.

ThingLab is described by wikipedia as a programming environment implemented in SmallTalk. In both cases, I think you are describing environments to play around with user-created objects moreso than languages.

Do Sketchpad or ThingLab have grammars?


Well, what is a language then? My opinion is that any abstraction layer that shapes thought and allows for the expression of new abstractions is a language in its own right. If it has a textual syntax, great! But this isn't necessary. It might be a programming environment that exposes new or different metaphors from its underlying host. An object system in Scheme is defining a new language, an enhancement of Scheme, that happens to be OOP.

SketchPad is a language, just a very inexpressive one that is not targeted at traditional programmers. ThingLab defines new metaphors and such, programming in ThingLab is a distinct programming experience from Smalltalk. Heck, even Bad Piggies is defining an inexpressive language in the context of a game, or think scripting in LittleBigPlanet.


I agree that you can "program" in these environments. But I disagree that they are languages. Perhaps I'm not thinking hard enough.


This is probably because what makes a "language" is fairly fuzzy. There is probably no hard line where a abstraction layer goes from just being a user interface/environment/library/notation to a language.


>but I observe that Smalltalk is what he in fact created as the manifestation of his ideas

Actually no. Dan Ingalls made Smalltalk-80, which is probably the one you know. Kay never liked ST-80, but I'm not convinced Kay ever had a clear vision of what OO should be, only what it shouldn't. He knows enough to say he doesn't like anything that's available but why hasn't he just made a manifestation of his ideas? It's much easier to deal with "no, not like that, like this" then someone who just constantly says "no, that's not it either".

There were several previous versions of Smalltalk. Maybe he actually did make some of those. But they were dropped because they weren't powerful enough...


He has. This post https://news.ycombinator.com/item?id=4789877 has more details.

But I think it was clear before this. Message-passing between non-shared state actors is a fundamentally different animal than "traditional" shared-state programing, whereas what is commonly thought of as OOP (special method-call syntax, class-based coding) is just sugar on any other language without changing the way things work under the hood.

Certainly, using the word "object" was unfortunate because it distracted people whereas "message-passing" is more to the point, but if you see what it was supposed to achieve there really is only one thing it could mean.


No argument. My comment was meant more as a lament- "oh, Object Orientation, what you could have been!" - than as a claim that we don't need something else.


Isn't that exactly what calling a method of an interface does?


  More subtly, passing around objects at all couples the program to the object 
  system — the rules for looking up the objects’ data and behavior is an 
  implicit global context. If the modules communicate by passing around 
  self-contained textual data, or a simple structured format like JSON, 
  then they impose fewer assumptions on each other. Different parts can be 
  written using different platforms or languages, allowing access to far more
  libraries. (They can also be on physically separate computers.)
I may be mis-reading this, but is the author advocating this sort of serialized message passing within local environments, not just between them?

Passing around data bags within local systems seems kinda odd given they have to be deserialized and mapped to a local object anyway. At that point you introduce an overhead of converting objects in the sender context, sending the data bag, converting that message to a an object usable in the receiver context and reverse the process when the method returns.

If you are passing around literal values in strings, then this doesn't matter, but if you are passing around JSON in strings, you end up with a general container that probably has to be inspected and categorized which seems contrary to the whole point of the article.

This is like an American company opening offices in multiple foreign countries and then requiring english to be the only language that can be spoken in those offices.


Hi. I'm the author.

I'm advocating breaking the system into modules with messaging between them, at a fairly course grain (i.e., between subsystems). Within the modules, do whatever you want, but I'm talking about decomposing a system into a service-oriented architecture, or multiple Erlang processes and applications, or Unix pipes, or whatever you want to call it. (Doing it at too fine a grain leads to lots of CPU churn from excess serialization, of course.)

JSON is a decent example of a neutral and lightweight protocol, but it's worth actually thinking long and hard about the shape those messages should take. (I prefer text or binary payloads, but I'm also doing embedded development and a real JSON library costs ROM.) Thinking hard about those interfaces/protocols between the pieces, and keeping them tight, is where the value comes from.

(Kind of a quick response because I'm at Clojure/Conj today, sorry if I'm missing part of your point.)


OK then, I misunderstood the paragraph. I took it to mean that you were enforcing a lowest common denominator type system across all calls, regardless of intra or inter system.

EDIT

Reading further, I guess it was the JSON bit that threw me off.

It seems that you'd want to have brokers at the edge of modules or in between them in this case. That's may seem architechty, but the reality is that you aren't coupling a module to any non native type representation. Objects go in, objects come out.


Each node can have its own type system, when it makes sense to do so. The arcs between them just need to agree on how they communicate.


Well, you could simply pass around data that can be round-trip (de)serialisabled to/from JSON, and if you need to send it outside the process, actually do real (de)serialisation.


This is object-oriented programming.

From Alan Kay, the inventor of Object-oriented programming:

> 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.[1]

[1] 2003. http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay...


I know. That's my point -- how far common OOP has drifted from that concept of object-oriented programming. (I'm the author of the post.)

It's a meditation on why Erlang feels more OO to me than (say) Java or C#.


Agreed - I actually wrote a post about this myself (in the context of comparing Java to Python)[1].

I'm just pointing out how ridiculous it is that the actual father of object-oriented programming thinks that the only object-oriented languages are two which don't even fit this "new" definition!

http://varnull.adityamukerjee.net/post/32394239181/objects-p...


It is good to see messaging become more popular! It has been around for a long, long time, but it has never been given the spotlight.

going meta for a bit...

When I see the number of comments here, I have optimism for the system that is distributing the important knowledge (the Internet and good online communities ( HN )). I don't think the ACM or any of the engineering related orgs are ahead of the curve on these things. Engineers need to share with engineers on this topic.

I just read the paper by Richard Gabriel on CLOS and Mixins. One of the tl;drs for that paper is that engineers are the driving most of the innovation in this field. (or at least as much as academia). This reinforces the point above.

In contrast, throughout the 80s,90s or even 00s, when I talked or asked about Smalltalk, Objects, and other interesting tech... I was usually told that those were failures. "Go with C++ or Java". Those languages are the very ones that made MOP and other interesting paradigms feel like you were going against the grain.

Even if you were following some usenet newsgroup that had good discussion. There was usually a bozo factor or too much religion (aka not much cross pollination)

So glad to be in the future and see positive discussion occurring!

... going un-meta

tl;dr - It is good to see people look at the existing paradigms with an open mind. just like functional programming. Overall the post linked to is not that interesting. It is the discussion in the comments here that is inspiring.


The asynchronous aspect of this is a big deal. It makes life both easier (because components can continue to run without blocking on data) but introduces complexity (sometimes you /need/ to synchronize). I've recently been working on a research project where this difference became very apparent. If you're working with wall-clock time (and especially any deadlines) the synchronization between different processes can subject you to needing a real-time operating system. At the very least (without deadlines) you're going to be doing some semaphore coding which can be difficult to scale.

On a related note: I look forward to the new Intel Haswell architecture. Built in HW Transactional Memory!!! Hurray!


Recently back from QCon SF, one of my favorite bits was a tutorial given by James Lewis from ThoughtWorks on micro-services (which he said was not the best moniker but close enough that people understand the idea). Lots of resonance with the concept described in this post -- use existing APIs and formats to create "just enough" architecture to connect distinct components in well-defined ways.

Slides from an ealier version of the talk here: http://www.slideshare.net/jamesalewis/java-microservices


This made me think about stevey's google platform rant, when he talks about internal API's being the key to amazon success.

link : https://plus.google.com/112678702228711889851/posts/eVeouesv...

Very good article by the way. Not very thorough, but that's what is good. It just remembered me about a state of enlightenment i have already felt, but forgotten since.


I too am on the Message Oriented bandwagon. I even wrote my own ORM (https://github.com/agentgt/jirm) because the current Java ORMs (Hibernate) kind of suck for messages where you generally want immutable objects.

The biggest problem I have had so far is Java is just not as friendly for this kind of architecture compared to Scala.


If you declare message passing as the only true form of OO then you're just drawing your box too big. Within the infrastructure that allows you to pass those messages around are many interesting lower-level problems that require the uglier, statically typed and binary-incompatible OO programming maybe better described as class based programming.


THIS.

My current work involves managing a range of different concurrency and multi-process systems. Focusing on clean, forgiving message channels as the foundation of the system has been a win in the last three very different problem spaces. Only thing missing is perhaps a nod to Communicating Sequential Processes.


I (the author) prefer Erlang's async messaging style, because CSP seems to assume that the messaging is reliable. Otherwise: Yes, definitely.


Have a look at ROS.org, its the same system you jsut reinvented (even with kinect intergration!). You write typed messages and it generates c++, python and lisp interfaces. It is also a build system, logging and data playback.


Most of the work was on the hardware side, and I'm being deliberately vague there due to NDA.


Anyone give me a good OOP open source program so I can learn from the source?


I would search for "Squeak By Example" and read through the book. It is Smalltalk, aka the seminal OO language. It also provides all of the code use to create the system and the VM it runs on in a readable, editable, runnable format so you can play with everything. Reading the code was really eye opening for me. And super fun to boot!


Pardon the evangelization, but this is precisely one of the strengths of node.js; being network-focused means it's very easy to build a collection of small services instead of a monolithic server.


I'm surprised that no one thus far has mentioned that message passing is just a special case of multiple dispatch. In that light, it seems less expressive. Any thoughts?


Message passing allows you to code the individual components in multiple languages on multiple platforms that run at multiple speeds. The thing that makes it work, however, is that the sender also has a queue, and work-completed messages go into his in-queue, in the order completed, so there is no need of mechanism to collect the results of multiple dispatches, nor is there a need to pass along with the message what function needs to be called on message completion, since the caller queue handler will do that.


Well, I've wanted to make a lightweight JSON-superset language with some sort of piping or message-passing ability. Perhaps this is my chance.


"Writing to interfaces" is a core concept of OOP.


How does this relate to Flow Based Programming?




Consider applying for YC's W25 batch! Applications are open till Nov 12.

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

Search: