When one object is "calling a function" inside of another object, it's reaching into that object, grabbing the method it wants to invoke, and invoking it. It puts the responsibility of invoking that method on the caller.
When one object "sends a message" to another object, the receiving object is responsible for determining what function gets invoked.
The most obvious place this difference manifests itself is the existence of things like "method_missing". That can't happen when you're "calling a function", but if you're just sending a message and the receiving object doesn't have a method that matches the message name, it can still make a decision about how to respond.
Messaging is much more flexible - the receiver can have a custom dispatch function that looks at the message and chooses the implementation in a Turing-complete way (like "call foo if third argument is 7, bar otherwise"), logs the message, duplicates it to send to multiple implementations, serializes it to send over the network, whatever.
Obviously for this to be efficient, the underlying system often optimizes "sending a message" to "calling a function".
The Kay Object (KO) is more of an encapsulated microservice, like an Erlang process.
How would mail (SMTP) look if it was implemented via RPC?
[1] I specifically didn't use the word object because the Kay Object and the Java/C++ object are not comparable.
The funny thing is, we now do have a lot of systems that are async message-oriented. Mostly in Javascript, not Smalltalk. You send a one-way message to something, and maybe it calls you back later.
Great quote along these lines is: Upgrade cost of network complexity: The Internet has smart edges ... and a simple core. Adding an new Internet service is just a matter of distributing an application ... Compare this to voice, where one has to upgrade the entire core. - RFC3439 (2002) ... from my fortune clone @ https://github.com/globalcitizen/taoup
If the object supports the message, then it will execute some code. Otherwise it will just ignore it. This is a more dynamic approach than an explicit function/method call where the object must support that function.
You can think of e.g. Javascript events plus function calls (callbacks) that pass an object ("message") and a typeof/switch check as an equivalent.
- function calls: single recipient, return values, synchronous
- messaging: publish & subscribe, no return value, asynchronous
Also - using pure message passing "inside" a component is kind of painful, using pure function calls between components can be painful. Of course, this depends on your definition of "component"....
What is the difference between "messaging" and "function call"?
"messaging" data into a module = call a function with the data as arguments.
"messaging" data out of a module = package the data as the return of the function.