Are messages in Ruby implementation details or fundamental

My understanding is that calling a method on a Ruby object sends messages to the object (which can be done manually with a method send

).

When I use Python I don't think about how the method / function call is handled; if it is defined or available then it is executed, otherwise I get an error.

1) Unique use of Ruby messages (i.e. Python also uses messages under the hood)?

2) Does Ruby post only an implementation detail or is fundamental to how you should use Ruby (i.e., I'll be missing something if I ignore it and keep calling my methods like in Python)

+3


source to share


4 answers


1. Are messages unique to Ruby?

This idea of ​​calling methods as sending messages is not unique to Ruby, it is an ideology that derives from Smalltalk , from which Ruby inherits many ideas. As a result, other descendants of Smalltalk also use the messaging system (for example, Objective-C, Groovy, and yes, Python uses it too ). Smalltalk is one of the first OOP languages, and it is very highly paradigm-tuned, so you will see many of its ideas in other languages.

Other OOP languages

Other languages ​​(especially those that support OOP) also (sort of) use messages in different guises (for example, "virtual function call" or "dynamic dispatch" in C ++ and Java, respectively). The difference here is that you, the programmer, do not access the messages directly, they are an implementation detail of the language, not your program, so if you send an unsupported message in C ++ or Java, it will result in an error (if lead time).

Messages in Ruby



The thing about Ruby is that the methods you can call (messages you can send) are independent of the type of object you call them on. You can send any message to any object, but those who do not have this message implemented as a method will do what they are told method_missing

. This means you can control what happens when an unsupported message arrives (if you like).

2. Does this have to change the way I write programs in Ruby?

The short answer is yes. But the point is, it probably already has: Ruby is not statically typed, so there is no way to know what methods you can call on the object contained in the variable anyway (there are no "compile-time" guarantees). Also, knowing that message passing is used under the hood allows you (when you need to) override the implementation method_missing

to create very expressive classes. The Rails framework does this to implement some of its DSLs.

Adding. Don't abuse it!

As with anything, this feature can be abused. You can only write one method in your classes ( method_missing

) and then write all your method definitions there. But the more logic you put in method_missing

, the harder it is to understand your class. So, if possible, define a method and handle this metaprogramming as a last resort.

+4


source


Messages are fundamental not only in Ruby, but in OO in general.

The term "Object-Orientation" was invented by Alan Kay and he defines it this way :

OOP to me only means messaging, locally holding and protecting and hiding the state process, and ultra late binding of all things.

In more modern terms:

  • messages
  • Encapsulation
  • late binding

Implementation, messaging is a late-bound procedure call, and if the procedure calls are late-bound, then at design time you cannot know what you are about to call, so you cannot make any assumptions about the particular state representation. So actually it is about messaging, the last binding is messaging implementation and encapsulation.

He later clarified that "The big idea is messaging, " and regrets calling it "object-oriented," message-oriented, "because the term" object-oriented "focuses on the irrelevant thing (s) and distracts from what's really important (messaging):

Just a mild reminder that I put in a bit of effort on the latest OOPSLA to try and remind everyone that Smalltalk is not only NOT its syntax or class library, it's not even about classes. I wish I had coined the term "objects" for this topic a long time ago, because many people focus on a smaller idea.

The big idea - "messaging" is something about the Smalltalk / Squeak core (and this is something that was never fully completed in our Xerox PARC phase). The Japanese have a small word - ma - for "what's in between" - possibly the closest English equivalent to "interstitial". The key to building large and resilient systems is much more to define how its modules interact, rather than what their intrinsic properties and behavior should be. Think of the Internet - in order to live it (a) must allow many different ideas and implementations that go beyond any single standard, and (b) allow varying degrees of secure interaction between those ideas.



(Of course, today most people don't even focus on objects, but classes, which is even more wrong.)

Messages are fundamental to OO, both as a metaphor and as a mechanism.

If you send a message to someone, you don't know what to do with it. The only thing you can observe is their response. You don't know if they were handling the message themselves (i.e. if the object has a method), if they forwarded the message to someone else (delegation / proxying), if they even understood it. What is encapsulation, what is OO. You cannot even tell the proxy from the real thing as long as it reacts the way you expect it to.

A more "modern" term for "messaging" is "dynamic method dispatch" or "virtual method invocation", but that loses the metaphor and focuses on the mechanism.

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

Dynamic dispatch of transactions is an essential characteristic of objects. This means that the called operation is a dynamic property of the object itself. Operations cannot be statically identified, and there is generally no way to accurately perform any operation in response to a given request, other than by running it. This is exactly the same as with first class functions that are always dynamically dispatched.

Smalltalk-72 didn't even have objects! There were only message streams being sorted out, rewritten and redirected. Methods first appeared (standard ways of analyzing and redirecting message streams), later objects appeared (groupings of methods that share some private state). Inheritance appeared much later, and classes were introduced only as a way to support inheritance. If Kay's research team already knew about prototypes, they probably would never have introduced classes in the first place.

+5


source


It is a fundamental metaphor for non-static evaluation of methods. The value, for example. one instance can have additional methods not defined in the class.

Or, if the method is unknown, it is handled by a special method method_missing

. Which can be overridden to add "bogus methods" that are never defined, for example. for example ActiveRecord

when it dynamically recognizes attribute names as methods.

Thus, unlike other "static" languages, there is dynamic method evaluation, so the "send message" metaphor is used rather than just "function call". "function call" assumes the "function address" is known, and in ruby, the estimation of which method to call, if any, is completely dynamic.

That being said: It doesn't matter when starting out with ruby, and honestly for me personally, this concept of "sending messages" confused me at first because I just wanted to "call methods" :)

+1


source


Fundamental. Messaging is a quirky buzzphrase in computer science, which is why Ruby is now this hot messaging-based language. But words aside, think:

Array.class_exec do define_method "42" do self << 42 end end

      

Array won't let you write

[].42 #=> SyntaxError

      

But 42

now is still a valid message that the array responds to:

[].send "42" #=> [42]

      

In other words, if you don't think in terms of messages, you cannot use 100% of the power of Ruby.

As for Python, which calls a Python method, for example foo.bar()

, what happens is that you first get the method object ( foo.bar

) and then when you hold on to it, you call it with ()

. In Ruby, you can get a method foo.method( :bar )

and then call it if you like .()

, for example:

x = [1]
x.method( "42" ).()
#=> [1, 42]

      

This makes the basic messaging mechanics a little more explicit.

0


source







All Articles