Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

How is messaging different than calling a method?


One example is the HTTP GET request. This was originally conceived of as a file download, where the URL path is mapped directly to filesystem paths. GET as an RPC: "download the file at this location."

But in modern thinking, HTTP GET is a request with abstract semantics. The URL's path is abstract, and may be interpreted arbitrarily by the server. The client has no idea whether the request is serviced by a simple sendfile() or a fully dynamic program. HTTP GET is no longer an RPC, it is now a message.

A key difference is whether your function call is a request for concrete or abstract behavior. If you answer "abstract," then the call itself must be reifiable data, which can be sliced and diced in ways hidden from the caller.


As defined in both RFC 1945 and 2616 (that is, as always has been defined): "The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI."

The thing is that there's no difference between abstract and concrete semantics in terms of definition of what is a function or message and what is not. You can send a message or call a function with very concrete semantics ("please, check if that file exists") or with something very abstract ("please, execute a job").

The real difference of the message and function definitions is how they are executed. With message you pass the information on what do you expect to be done to the underlying infrastructure, which has to find the actual code to complete the delivery. With functions you are supposed to know, what exactly code you are calling.

In modern world the discussion about these differences in context of OOP classes does not make much sense: virtual methods of interfaces do their job as well for local invocations (JVM in Java world or VMT in C++ does the binding job), so it does not matter whether you call them messages (which may be right, considering dynamic nature of the call) or functions (again, it's correct, because as in C++ case there's no special mediator passing the call and in Java JVM is practically invisible to application programmer). The cases, when message delivery does not coincide with invocation of single method are rare and normally solved with application level architecture (design patterns like Facade are good example of the solution).

What's more important, IMHO, is that this talk about importance of messages is no more relevant to current problems of object-oriented programming. I do not think today we are really concerned about object interactions, rather we have to fight the enormous complexity of big projects, finding better ways of generalization (by means of more expressive languages and metamodels) and API contract clarification and enforcement (by elimination of side effects and correct handling of corner cases).


HTTP GET was initially defined to "Please transfer a named document back." [1]. The idea of interpreting the path to dynamically generate a document came later. If you like, you can think of it as a shift from Apache-circa-1999 servers that expect to deal primarily in files, to Rails-style servers that primarily route requests to dynamic code.

You're right that design patterns like Facade are often used instead of exploiting messaging. But this comes at a price: clients are necessarily aware that they are talking to a Facade. Discovery and negotiation are done statically, via the type checker. Versioning is static too. Everything it tightly coupled.

Say you have a String, and you want to concatenate it with another String. You check the docs, or StackOverflow, or IntelliSense, right? What you don't do is use Reflection to list all the methods, and pick based on their name. And you certainly don't feed an input to each method, and pick the one that gives the right output! (This strategy is routine in Smalltalk! [2])

Now say you want to build a web search engine. Do you try to statically build up website descriptions? Maybe you check StackOverflow for the HN link structure, catalog it for everyone? No, you start at the root, interrogate it, and build the link graph as you go. You have a conversation with the remote site, and perform discovery dynamically.

That's messaging! And that's why URLs are a better example than most modern programming languages: the value of OO is best realized when you have loosely coupled components, like on the Internet. (Alan Kay wrote that every object should have a URL. [3])

[1] http://www.w3.org/History/19921103-hypertext/hypertext/WWW/P...

[2] http://wiki.squeak.org/squeak/1916

[3] https://ivanovivan.wordpress.com/2010/09/13/alan-kay-quotes/


Well, the remark about the acceptable format in the same definition from 1992 means that there's dynamic processing of the request, which may involve the document conversion at least. And it does not say "file", which means that there can be a database as a document storage. In 1999 the web was mostly dynamic (I myself was using PHP, Informix WebConnect, Java and C for web development by that time) and more abstract RFC 1945 came in 1996 (just 4 years later), 1 year after Amazon went online. The period of time, when GET could mean only "give me a file" was in fact very short, if ever existed.

Then, you write that Facade is "tightly coupled". In fact, it's not more coupled than any native messaging. Let's say, the client code wants an object, representing a coffee machine, to prepare latte with temperature about 40C. There are other things, that coffee machine can do (e.g. self-check), so you need to pass 3 facts to it: "prepare drink", "drink type is latte", "temperature is 50C". You indeed can send a message to this object, containing these 3 facts as message data. Or you can call a method "prepare" of API with 2 parameters. See, there's no difference in amount of information you use for this operation: either way, there are 3 facts, for which you use 2 different syntactic forms. Coupling by definition is amount of shared information about mutual state and behavior between components (number of facts fixed in interaction contract). Here it's the same.

With all that in mind, modern languages are so rich in syntax, that there's almost no use case for messages as the means of interaction between objects at this moment. When you mention reflection, I'd say it's not the same. You use reflection to discover the address of the routine to call (that is, do not rely on infrastructure for delivery), rather than deliver the message to the object so it could dispatch it itself. Well, of course, there's one remark - this depends on how you define the message. Reflective calls are late binding just the same way as dependency injection: in runtime some container or reflection API provides an address of the code, implementing given interface, that will be invoked. If reflection means messages, then DI means messages, then VMT means messages, then messages=methods and all this talk is about outdated definition of what everyone uses.

Web crawlers are a bit different story: search engines do not deal with objects, they always deal with documents, that do not expose any behavior. The only thing in the net that comes to my mind is the semantic web. There were talks about it in early 2000s, when there was a lot of hype about web services, runtime discovery, web ontology language etc, but it's now as dead as CORBA.


Can you define "reifiable" for me? I come across it a fair bit in clojure, but I still don't really understand what the term means.


Reifying means to take the abstract and make it concrete. Reflection is an example: take a language feature, like a class, and make it into real data. Many languages have some reflection capabilities for types; message sending takes this even further.

For example, in Java, I can take a class and make data out of it: dynamically look up fields, etc. I can also do that with a method. But I cannot take a method call and turn it into data. I can sort of do it with a lambda, but lambdas make poor data:

1. A lambda is concrete, not abstract. It's literally "run this code." 2. Even if your lambda merely invokes a method on an object, it's still opaque. I can't pick it apart, get the parameters or method name out, etc.

Here's some practical objects you can't make in Java:

1. Envelope: wraps an arbitrary remote object Contents. Any method you invoke on Envelope gets sent over the wire and invoked on Contents.

2. Delegator: represents the union of one or more objects, the Delegates. Any method invoked on Delegator gets re-sent to the first Delegate that understands it.

3. Tee: Any method you invoke on the Tee gets multicast to its wrapped objects.

4. Mapper: wraps a list. Any message you send to Mapper sends it the elements of its list, and returns the resulting list.

etc. Put directly, Java method invocations are procedure calls, not messaging. But once you reify method invocations into object, it opens up all sorts of dynamic possibilities.


thanks


"reifiable" = "able to be reified", where "to reify" means "to make something abstract concrete or real".

So, for example, Scheme's call/cc function reifies continuations- it take a continuation, an abstract control-flow concept, and turns it into a concrete object that you can pass around and manipulate in code. Therefore, continuations are reifiable in Scheme.


thank you


The other comments have already answered this well enough. If you want a little more reading this is a nice example of an application of reification [0]. The first few paragraphs define it well, and then shows examples for implementing it for handling user/actor input and actions in a video game.

[0] http://gameprogrammingpatterns.com/command.html


I'll buy that



So... it's basically event-driven programming? Objects generate events, and other objects are free to subscribe to them and do something in response (or not)?

I thought of something similar a few years ago, I think it would indeed enable much better decoupling than the current OOP model - instead of object A telling object B "do this" (and thus having to know that object B exists and that it can do "this"), have object A emit an event "I just did this" and let object B, if it's interested, handle that.

There's still the problem of "now B has to know about A", but it can be solved with a common event bus and a series of messages defined in a different library - that way both A and B only know about the common library, they can be completely independent of each other.

I wrote something like this a few years ago - just added it to my GitHub at https://github.com/mdpopescu/public/tree/master/Snake - but I can't say I ever did something "serious" with it. It's one of the things I'd like to actually use in production, like CQRS/ES or Orleans :)


> subscribe

There isn't any subscription with messages, which are sent to the object directly. There isn't any "event bus" or other complex structure. Messages are just a replacement for function calls (including accessor methods, which may be implied).

> decoupling

That's one of the primary goals. Traditionally function calls required coupling between the call and a single function or multiple functions with vtables or other polymorphism. With messages, the handling of what looks like a function call can be interpreted like an incoming event in event-driven programming.

> let object B, if it's interested, handle that

That's exactly right, but think of it as:

    * Object A sends Object B an event (message)
    * Object B can then handle that event in any way, such as:
        - calling a function
        - interpreting the event directly (i.e. all events handled the same)
        - raising an exception
        - ...whatever...
    * Object B then returns the result which becomes
      the "return value" that Object A. (this part is RPC-like)
> now B has to know about A

Not at all! I suspect you're thinking of this as a subscription model, which isn't correct.

One of the key benefits of messages is that objects never need to know about each other's type (in either direction). Ignoring types and simply sending messages to objects (regardless of their type) is called "duck typing"[1]. As long as an object responds in a useful way to the messages ["year", "month", "day"], it isn't important if the object is actually of type Date.

[1] http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/...


I have to admit I still have basically no idea what he's talking about when he says 'messaging'. A practical example would be useful for us non-CS-degree programmers who don't speak any of the CS lingo.


Imagine two solutions to a problem.

One has a main procedure that orchestrates itself and other code to work things out and do things. This is the way most people organize their problems into code.

The second is a set of independent intelligent concepts (objects) that work together to work things out and do things. The objects work together only by sending messages to each other. There is no central code orchestrating them into a solution.

If you want an example, consider two tennis players and a ball. How would your represent them hitting the ball to each other in code?


For me there's a disconnect in the handling. So in a traditional approach, you write one function that takes in input and spits out an output (called, say, FUNCTION_A).

Then you have another function (FUNCTION_B) that maybe does some stuff and then calls FUNCTION_A with an internal variable and bam you're done.

In messaging, FUNCTION_B doesn't call FUNCTION_A. It just shouts out (or sends a message containing) something like "I need to turn my internal variable into a given output". Somewhere in the application will be a process that listens out for just that message and then does something in response to it.

So you have all these modules (or cells in some examples) that are shouting out things and then you have other cells (or a single brain) that take in all the messages that are being shouted and do stuff based on the content of the message. You could think of a stock market trading floor (with a whole bunch of people scrambling and shouting stuff, although obviously much more orderly in a program) or the cells in your body that send messages to your brain (like cells in your fingers sending "the human is putting his hand on a hot stove, tell him to take it off before us little cells die" and then your brain - and you - react).


The idea is to replace "calling a function" with "sending a message".

Traditionally a function call is fixed at compile time (with some exceptions such as function pointers). In C a function is just an address; if we want to call foo(), we must have that function available at address &foo. C++ added flexibility by allowing there to be multiple functions called foo() with and a set of vtables[1] that store the actual (C-style) address. Other variations exist, but all of these traditional styles map function calls to specific code that runs every time the function is called.

Message change all of that. Instead of vtables (or similar)

    obj = create_foo()

    # instead of calling foo's bar() function directly, e.g.
    foo_bar(obj)
    # or perhaps
    obj.bar()
... we send a message by name of the function we want to call to the object itself

    obj = create_foo()
    obj.send_message("bar")

    # if function args are needed, include them as an array
    obj.send_message("baz", [42, "quux"])
The idea is that while the message can be effectively the same as a function call, it doesn't have to be. In a proper OO language, this message sending is handled automagically by the syntax.

    # instead of handling the messages directly, e.g.
    obj.send_message("bar")
    # the language does that for you when you call
    obj.bar()
    # in some languages, these are equivalent
In many cases the "foo" class above will handle the message "bar" by running the appropriate function, but that isn't required. For example, in ruby when no function exists for a given message, the raw message is send to the #method_missing function.

    class Foo
      def method_missing(name, *args, &block)
        puts "#{self.inspect} I was sent message #{name.inspect} with args #{args.inspect}"
      end  
    end  

    >> obj = Foo.new
    => #<Foo>
    >> obj.bar()
    #<Foo> I was sent message :bar with args []
    => nil
    >> obj.any_name_we_want()
    #<Foo> I was sent message :any_name_we_want with args []
    => nil
    >> obj.any_name_we_want("args", "are", "optional")
    #<Foo> I was sent message :any_name_we_want with args ["args", "are", "optional"]
Thinking of "obj.method()" as a message instead of only a function is much more flexible.

[1] https://en.wikipedia.org/wiki/Virtual_method_table


thanks, that was a nice explanation


Short Answer:

Calling a method is "Command and Control" where "command" is about getting a thing to do something that you want, and "control" is about preventing a thing from doing something that you don't want. In any case, you're running the process.

Message passing is about negotiating with something that is already in process. It turns out that this is the key to building scalable¹ systems (for all the usual reasons: enforcing loose coupling, abstraction, decentralization, etc.)

Longer Answer:

1. The actual powerful thing about a general-purpose computer is that it can simulate anything, including a "better" general-purpose computer (think about what Universal Turing Machine means).

2. Recursion is about making the part as powerful as the whole

Putting those two together leads to the original insight behind OOP: Why not build systems out of (scaled-down) computers!

So, in de-jure OOP, objects are supposed to be computers. Sometimes they are general-purpose computers (i.e. they contain an interpreter for a "Turing Complete" programming language), often times they are more limited special-purpose computers (e.g. functions, procedures, programs, etc.) . Crucially, the only way to interact with a computer/object is to send it input and receive output. It's completely up to the computer as to how to interpret the message (n.b. each object contains an interpreter). I like to think of OOP as being about scaling computer networks in both directions: scaling up gets you something like the Internet, scaling down can get you something like desktop publishing (I recall that Alan Kay said something like desktop publishing was really just about getting rid of the borders between apps).

While, in theory, method calling and message passing are equivalent, the problem with method calling is that it tends to limit you to building systems out of mere data structures that just happen to have all of the functions/procedures conveniently "nearby". Data structures are good if you want to make a process, but lame when you need to deal with one.

¹Scaling to me means that, with respect to some metric, there is a point at which the difference between the addition of part_n and the later addition of part_(n+1) becomes negligible. A part can be lots of different things: e.g. a user (metric is performance), an edit to the codebase (metric is pain), a new compute node in a network (metric is cost), etc...

(For the mathematically inclined, I think scaling is about making sure that the sequence of steps for building a system is Cauchy.)


Thanks! This is a great description of what I think Alan is trying to describe. The issue most people seem to be facing is that they are trying to map his ideas of messaging onto their current conceptions of what software should look like, instead of stepping back (way back) and saying - how would a bunch of Universal Turing Machines communicate? Software today is fixed functionality - once it's written it can only be changed with great pain. What if we made meaning and interpretation of messages 'late-bound'?


I think it could be different if the intention is that the message (or method body) is always executed in the context of the called object. E.g. in an own thread, which is used instead of the thread/callstack of the the caller, and which is also exclusivly used even if the method is called from multiple threads - which would elide the need for synchronization.

However as far as I understand most implementations that talk about messaging (e.g. ObjectiveC) do exactly the same thing as plain method calls. The difference seems to be that there is more dynamic in the "messaging" (can send any message to an object or can write a "method" that processes arbitrary messages) - but for me that sounds more like the difference between static and dynamic languages than as a completely different messaging concept instead of methods. I don't know Squeal and Smalltalk so maybe I'm missing something here


It implies more flexibility, like generically accepting messages, passing them on without knowing anything about them etc.


Same thing. The difference is that you are not required to construct class hierarchies in order to perform messaging.

Messaging works perfectly well in a composition-over-inheritance setting. See also: Erlang.


For dynamically typed languages, this distinction is less pronounced, but in general, the caller assumes less about the callee (i.e. you can send any message to any object).

It also allows transparent routing/delegating and, in some cases (void result type), transparent multiplexing.


A "method" is just a programming construct. A message in OOP is sent to an object to tell it to do something itself.

In an OO approach, rather than have a Hammer hit a Nail, the Hammer sends a message to a Nail which knows how to be hit.


That makes me wonder though, if i send a message to the same object from two different senders, will the first message affect the outcome of the second? If not then there is plainly little difference between the two, as either action gets a new pristine instance. All in all, this seems to be a whole lot of syntactical hair splitting.


What an object does when it receives a message is hidden, and entirely up to that object.

>>> All in all, this seems to be a whole lot of syntactical hair splitting

Or, simply a case of not understanding.


Or not having the 10000 feet outlook.

Checking some links to Kay's responses elsewhere, i get the impression that unless we basically toss the notion of a programs as a singular compiled file of binary, and replace it with some kind of abstract notion of work that can happen on a single computer, or across the net as a whole, the distinction between a message and a method is academic at best.

Because for message as a concept to make sense, it has to be seen as someone standing on a rooftop shouting "can someone please hit that nail?!", and then wait around until someone shouts back "done!".

Without that you just end up with a carpenter talking to himself "hit nail, done, hit nail, done, hit nail, done".


Yes, exactly. Step back (wayyyyyyy back) from your current understanding of what software should look like.


Even Wikipedia seems to conflate the two...

https://en.wikipedia.org/wiki/Method_%28computer_programming...


It's not different.


It's mostly not, that's the point. The difference is in the mental model.




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

Search: