7 ms·
How is messaging different than calling a method?
by elchief 10y ago
How is messaging different than calling a method?
- achamayou 10y agoIt implies more flexibility, like generically accepting messages, passing them on without knowing anything about them etc.
- dang 10y agoAlan commented on this several times in the AMA he did here a couple days ago: https://news.ycombinator.com/item?id=11957001 https://news.ycombinator.com/item?id=11957001 https://news.ycombinator.com/item?id=11945986 https://news.ycombinator.com/item?id=11945986 https://news.ycombinator.com/item?id=11945123 https://news.ycombinator.com/item?id=11945123
- stinos 10y agoI 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.
- pdkl95 10y agoThe 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 https://en.wikipedia.org/wiki/Virtual_method_table
- stinos 10y agothanks, that was a nice explanation
- michaelscott 10y agoFor 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).
- aryehof 10y agoImagine 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?
- mdpopescu 10y agoSo... 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 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 :)
- pdkl95 10y ago> 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/100511 http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/...
- InclinedPlane 10y agoIt's mostly not, that's the point. The difference is in the mental model.
- mietek 10y agoSame 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.
- ridiculous_fish 10y agoOne 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.
- elchief 10y agoI'll buy that
- DigitalJack 10y agoCan 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.
- gliese1337 10y ago"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.
- DigitalJack 10y agothank you
- ridiculous_fish 10y agoReifying 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.
- _pmf_ 10y agoFor 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.
- Matthias247 10y agoI 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
- jcoffland 10y agoIt's not different.
- noblethrasher 10y agoShort 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.)
- infinite8s 10y agoThanks! 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'?
- aryehof 10y agoA "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.
- digi_owl 10y agoThat 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.
- aryehof 10y agoWhat 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.
- digi_owl 10y agoOr 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".
- infinite8s 10y agoYes, exactly. Step back (wayyyyyyy back) from your current understanding of what software should look like.
- digi_owl 10y agoEven Wikipedia seems to conflate the two... https://en.wikipedia.org/wiki/Method_%28computer_programming%29 https://en.wikipedia.org/wiki/Method_%28computer_programming...