How exactly do "Objects communicate with each other by passing messages"?

44,723

Solution 1

If we are talking about OOP than the term "message passing" comes from Smalltalk. In a few words the Smalltalk basic principles are:

  1. Object is the basic unit of object-oriented system.
  2. Objects have their own state.
  3. Objects communicate by sending and receiving messages.

If you are interested in Smalltalk take a look at Pharo or Squeak.

Java/C#/C++ and many other languages use slightly different approach probably derived from Simula. You invoke a method instead of pass a message.

I think this terms are more or less equivalent. May be the only interesting difference is that message passing (at least in Smalltalk) always rely on dynamic dispatch and late binding while in the case of method invocation one can use static dispatch and early binding too. For example, C++ (AFAIK) does early binding by default until "virtual" keyword appears somewhere...

Anyway, regardless of which formalism do your programming language use for communication between two objects (message passing or method invocation) it's always considered a good OOP style to forbid direct access to instance variables in Smalltalk terminology or data members in C++ terminology or whatever term is used in your programming language.

Smalltalk directly prohibits access to instance variables at the syntax level. As I mentioned above objects in Smalltalk program can interact only by passing/receiving messages. Many other languages allow access to instance variables at the syntax level but it's considered a bad practice. For example, the famous Effective C++ book contains the corresponding recommendation: Item 22: Declare data members private.

The reasons are:

  • syntactic consistency (the only way for clients to access an object is via member functions or message passing);
  • more precise control over the accessibility of data members (you can implement no access, read-only access, read-write access, and even write-only access);
  • you can later replace the data member without breaking your public interface.

The last one is the most important. It's the essence of encapsulation - information hiding on the class level.

The point about encapsulation is more important than it might initially appear. If you hide your data members from your clients (i.e., encapsulate them), you can ensure that class invariants are always maintained, because only member functions can affect them. Furthermore, you reserve the right to change your implementation decisions later. If you don't hide such decisions, you'll soon find that even if you own the source code to a class, your ability to change anything public is extremely restricted, because too much client code will be broken. Public means unencapsulated, and practically speaking, unencapsulated means unchangeable, especially for classes that are widely used. Yet widely used classes are most in need of encapsulation, because they are the ones that can most benefit from the ability to replace one implementation with a better one.

(с) Scott Meyers, Effective C++: 55 Specific Ways to Improve Your Programs and Designs (3rd Edition)

Solution 2

Not exactly an answer to your question, but a little digression about message dispatch vs. method invocation:

The term message refers to the fact that you don't know which method will be invoked due to polymorphism. You ask an object to do something (hence the term message) and it acts accordingly. The term method invocation is misleading as it suggest you pick one exact method.

The term message is also closer to the reality of dynamic language, where you could actually send a message that the object doesn't understand (see doesNotUnderstand in Smalltalk). You can then not really speak of method invocation given that there is none matching, and the message dispatch will fail. In static typed language, this problem is prevented.

Solution 3

"Passing a message" is an abstraction.

Most OO languages today implement that abstraction in the form of feature invocation. By feature I mean a method an operation (see edit below), property or something similar. Bertrand Meyer in OOSC2 argues that feature invocation is the basic unit of computation in modern OO languages; this is a perfectly valid and coherent way to implement the old abstract idea that "objects communicate by message passing".

Other implementation techniques are possible. For example, objects managed by some middleware systems communicate by passing messages via a queue facility.

In summary: don't confuse abstractions with code. In the olden days, programmers used to care a lot about theory because programming barely existed as a mainstream profession. Today, most programmers are rarely familiar with the theory behind the code. :-)

By the way, and for the theory inclined, agent-oriented modelling and programming approaches often emphasise message passing as a communication mechanism between agents, arguing that it derives from speech act theory. No method invocation is involved here.

Edit. In most OO languages, you call operations rather than methods. It is the runtime engine which decides which particular method to invoke as a response to the operation that you have called. This enables the implementation of the so often mentioned mechanisms of polymorphism. This little nuance is usually forgotten in routine parlance when we refer to "calling a method". However, it is necessary in order to differentiate between operations (as features that implement message passing) and methods (as specific versions of said operations).

Solution 4

They're referring to the fact that a client can invoke a method on a receiving object, and pass data to that object, but that object can decide autonomously what to do with that data, and maintain its own state as required.

The client object can't manipulate the state of the receiving object directly. This is an advantage of encapsulation - the receiving object can enforce its own state independently and change its implementation without affecting how clients interact with it.

Solution 5

In OOP, objects don't necessarily communicate with each other by passing messages. They communicate with each other in some way that allows them to specify what they want done, but leaves the implementation of that behavior to the receiving object. Passing a message is one way of achieving that separation of the interface from the implementation. Another way is to call a (virtual) method in the receiving object.

As to which of your member function calls would really fit those requirements, it's a bit difficult to say on a language-agnostic basis. Just for example, in Java member functions are virtual by default, so your calls to a.methodA() and b.methodB() would be equivalent to passing a message. Your (attempts a) calls to b.methodA() and a.methodB() wouldn't compile because Java is statically typed.

On the contrary, in C++, member functions are not virtual by default, so none of your calls is equivalent to message passing. To get something equivalent, you'd need to explicitly declare at least one of the member functions as virtual:

class A { 
    virtual void methodA() {}
};

As it stands, however, this is basically a "distinction without a difference." To get some idea of what this means, you need to use some inheritance:

struct base { 
    void methodA() { std::cout << "base::methodA\n"; }
    virtual void methodB() { std::cout << "base::methodB\n"; }
};

struct derived { 
    void methodA() { std::cout << "derived::methodA\n"; }
    virtual void methodB() { std::cout << "derived::methodB"; }
};

int main() { 
    base1 *b1 = new base;
    base2 *b2 = new derived;

    b1->methodA();   // "base::methodA"
    b1->methodB();   // "base::methodB"
    b2->methodA();   // "base::methodA"
    b2->methodB();   // "derived::methodB"
    return 0;
}
Share:
44,723
Zaki
Author by

Zaki

SOreadytohelp

Updated on July 16, 2020

Comments

  • Zaki
    Zaki almost 4 years

    In several introductory texts on Object-oriented programming, I've come across the above statement.

    From wikipedia, "In OOP, each object is capable of receiving messages, processing data, and sending messages to other objects and can be viewed as an independent 'machine' with a distinct role or responsibility."

    What exactly does the statement mean in code?

    class A
    { 
        methodA()
        {
    
        }
    }
    
    
    class B
    {
        methodB()
        {
    
        }
    }
    
    
    class C
    {
        main()
        {
            A a=new A();
            B b=new B();
            a.methodA(); // does this mean msgs passing??
            b.methodB(); // or does this?? I may be completely off-track here..
        }
    }