What would be a good example of "sending messages to objects" within Python?
Asked Answered
P

4

6

I recently watched Nothing is Something by Sandi Metz, and in her talk she uses the idea of sending messages to objects and goes over how that's done in Ruby. The 4:10-7:30 section would be a good entry point where she begins on the topic (it's a building block that then permeates over half the talk).

Now, for some background: I don't have a lot of experience with writing programs in Ruby, and zero experience with smalltalk. My OO experience is somewhat limited and very stale. I also looked up send object message python in Google, and all I saw was relating to sending messages over sockets and email, which isn't quite what I had in mind.

I'm not sure how to interpret this concept in Python, or how to implement it. Any ideas? :)


Side note: She mentions her OO-views are derived from experience with smalltalk, so I'm adding that as a tag to this question.

Patroclus answered 4/11, 2015 at 23:47 Comment(2)
hah, at the part where she says: "Don't make a gem, don't put this on GitHub?" Sorry, I already did that over 6 years before she said it :-D joergwmittag.github.io/b001eArchibold
Most of the answers boil down to: "sending messages" in Smalltalk is "calling a method" in most other OO languages.Irina
T
11

Python uses a slightly different terminology. It is called "calling a method". But it's the same thing. (C++ calls it "calling a virtual function". Again, same difference.)

Personally, I don't like that terminology, it focuses too much on the implementation detail and loses much of the metaphoric power of the "message sending" terminology.

There are other differences with Python, some of the most important ones being:

  • object-oriented data abstraction is achieved via convention as opposed to being a builtin language feature (e.g. Smalltalk, Ruby), or Design Pattern (Scheme, ECMAScript)
  • not all subroutines are methods

The fundamental idea of OO is messaging: you send a message to an object, the object responds. Just like in real life, you have no idea what the object does with the message. All you can observe is the reply. The object might process the message itself, it might employ the help of others, it might blindly forward the message without actually doing any work itself.

Since you can't know what the object does with the message and all you can observe is the object's response, all you know about the object is its protocol (the messages it understands and how it responds to them). You don't know its implementation, you don't know its representation. That's how OO achieves Data Abstraction, Information Hiding, Data Hiding, Encapsulation.

Also, since each object decides independently how to respond to a message, you get Polymorphism.

One typical way of responding to a message, is executing a method corresponding to that message. But that is an implementation mechanism, which is why I don't like that terminology. As a metaphor, it carries none of the connotations I mentioned above.

Alan Kay has said that OO is about three things, Messaging, Data Abstraction, and Polymorphism:

OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things.

He later clarified that the Big Thing is Messaging:

Just a gentle reminder that I took some pains at the last OOPSLA to try to remind everyone that Smalltalk is not only NOT its syntax or the class library, it is not even about classes. I'm sorry that I long ago coined the term "objects" for this topic because it gets many people to focus on the lesser idea.

The big idea is "messaging" -- that is what the kernal of Smalltalk/Squeak is all about (and it's something that was never quite completed in our Xerox PARC phase). The Japanese have a small word -- ma -- for "that which is in between" -- perhaps the nearest English equivalent is "interstitial". The key in making great and growable systems is much more to design how its modules communicate rather than what their internal properties and behaviors should be. Think of the internet -- to live, it (a) has to allow many different kinds of ideas and realizations that are beyond any single standard and (b) to allow varying degrees of safe interoperability between these ideas.

And in fact, as I laid out above, the other two are just consequences of Messaging, in my opinion.

When Alan Kay came up with the term "Object Orientation", he was heavily inspired by what would later become the ARPANet and then the Internet: independent machines ("objects") with their own private memory ("instance variables") that communicate with each other by sending messages.

Similar points are also made in On Understanding Data Abstraction, Revisited by William R. Cook and also his Proposal for Simplified, Modern Definitions of "Object" and "Object Oriented".

Dynamic dispatch of operations is the essential characteristic of objects. It means that the operation to be invoked is a dynamic property of the object itself. Operations cannot be identified statically, and there is no way in general to exactly what operation will executed in response to a given request, except by running it. This is exactly the same as with first-class functions, which are always dynamically dispatched.

Python's object system is a bit different from other languages. Python was originally a procedural language, the object system was added later on, with the goal of making the absolut minimal amount of changes to the language as possible. The major data structure in Python were dicts (maps / hash tables), and all behavior was in functions. Even before Python's OO features, this minimalism shows itself, e.g. local and global variables are actually just keys in a dict. And so, it was natural to make objects and classes much like dicts and reuse that concept, an object is essentially a dict of values, and a class is a dict of functions. There is no separate idea of "method", rather, you have functions which take the receiver as their first argument. (In most other OO languages, the receiver is a "hidden" zeroth argument and available using a special keyword such as self, this, or me.)

Tridentine answered 5/11, 2015 at 0:37 Comment(5)
Epiphany-inducing blurb: "an object is essentially a dict of values, and a class is a dict of functions"Patroclus
Addressing the comment, "In Python object-oriented data abstraction is achieved via convention as opposed to being a builtin language feature (e.g. Smalltalk, Ruby)": It is actually purely a convention in Smalltalk too. It's entirely possible to make assignment statements to instance variables in Smalltalk. But the convention is to write accessors (getters and setters) for every instance variable, and then to always use those accessor methods by sending accessing messages.Danitadaniyal
@wTyeRogers correction, an object id's essentially a dict with a potential inheritence chain, and a Class is a function that constructs the object and it's potential inheritence chain.Chlodwig
2 years later, all of this is finally sinking in.Patroclus
@wTyeRogers: It took Nygaard, Dahl, Kay, et al. decades to figure it out, I think 2 years is pretty darn good :-DArchibold
W
8

Essentially "sending a message" is called in most of OO languages as calling a method. The key difference is that in dynamic languages you don't know if the object knows a method or not. So if you do var.jump() you have no idea what the var is. Maybe it's a rabbit and it can jump, or maybe it is a rock and it doesn't know how to do that (the Rock class does not implement the jump() method). So from conceptual point of view sending a message is asking some object to do something (maybe it does not know what you are asking), while invoking a method is making that object you know do what you want.

In Smalltalk and Ruby it's really easy to send messages with another message, so that if you use 1.send(:to_s) it's the same as 1.to_s. And 1.send(:to_s) itself is a message send that is sent to 1 with parameter :to_s. So you can also expend this to 1.send(:send, :to_s).

In Python meta programming is a real pain in the ass. So if you want to do the same 1.send(:to_s) you have to use something like getattr(1, "to_s")(). Here you obtain the to_s "method" itself using getattr and invoke it with (). This is also a good example of the bad Python design. How do you do something like 1.send(:send, :to_s) in Python? In Ruby send is a method on a code Object. So you can also send it via itself. In Python getattr is an external standalone function.

If you really want to learn the concept of OO programming I suggest you to play with Smalltalk because I find it to have the best design. (also it's not influenced by C++ or other stuff because in 70s they were not around). There is a nice book Pharo by Example that teaches you to program in . Also there is a work in progress version updated for the new releases of the environment.

Welcy answered 5/11, 2015 at 0:44 Comment(2)
Self and Newspeak are also very nice for learning OO. Self because it really drives home the idea that it's all about the objects and their interactions (there is nothing else in the system but objects), and Newspeak because of its absolutely fanatical adherence to messaging: there are no instance variables, only getter and setter methods, there are no class variables, only getter and setter methods of the metaclass, there aren't even local variable variables, only getter and setter methods of LexicalScope objects.Archibold
Even superclass lookup is a message send!Archibold
K
2

The core idea is called Message passing.

In python you normally send messages by the standard notation:

obj.methodname(args)

If the method name is dynamic, you can do this:

getattr(obj, methodname)(args)

Example:

>>> getattr("  12", "strip")()
'12'

Even though we usually use the standard notation, behind the scenes there's a request for the attribute which you can observe by intercepting the call:

class Test(object):
    def __getattribute__(self, name):
        print "requesting attr:", name
        return object.__getattribute__(self, name)
    def test(self):
        print "Hello"

>>> Test().test()
requesting attr: test
Hello
Kami answered 5/11, 2015 at 0:25 Comment(2)
In Smalltalk this message would have been ' 12' trim and its answer '12'.Lemniscus
@LeandroCaniglia, in Python it becomes ' 12'.strip(). The other constructions are for more general cases. I suppose you could write ' 12'.send(trim) or something like that in Ruby.Egwan
D
0

What started as "sending a message" in Smalltalk in the early 1970s, is now more generally known as "calling a method"

Sending a message is making a polite request to an object to respond. It will respond politely if it understands the message it receives, and has a method of responding. i.e. if the message is in the protocol of the receiver.

The protocol is the list of messages it has methods of responding to. Nowadays, we would call the protocol the receiver's API.

Alan Kay, the father of Smalltalk, felt that messaging, rather than inheritance, was the important aspect of what became known as object-oriented programming.

Danitadaniyal answered 7/11, 2015 at 3:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.