I’m a ruby developer and something that has confused me in the past has been the phrase ‘calling the method on X’ or ‘sending the message to X” where X is an object. It almost seemed like people were using the two phrases interchangeably when describing a method call on an object.
So which is right?
The answer, perhaps unsurprisingly, is both! Let’s look at why.
Let’s think about an object in Ruby for a moment. Say you have an instance of the String class and you assign it to the variable example_object
example_object = "This is a string"
Okay, so our object has a bunch of methods available on it, in fact as an instance of the String class it has all of the instance methods that are included by default.
Sending the messages
I can send any message I like to our object with the .
notation. I can send the message made_up_message_that_wont_work
to it as such:example_object.made_up_message_that_wont_work
. Sending a message doesn’t mean that it will work, as it won’t in this case, but the point is that I can send any message I like, and when using dot notation it’s represented as the right hand side of the dot.
Calling the method
First of all, let’s check what methods we can call on our example_object
. We can do that by sending the message methods
to the object which will then call the correspondingly named method (the methods
method).
>> example_object.methods
=> [:include?, :%, :*, :+, :to_c, :unicode_normalize, :unicode_normalize!, :unicode_normalized?, :count, :partition, :unpack, :unpack1, :sum, :next, :casecmp, :casecmp?, :insert, :bytesize, :match, :match?, :+@, :-@, :upto, :index, :<=>, :replace, :succ!, :next!, :getbyte, :==, :===, :byteslice, :=~, :chr, :[], :[]=, :clear, :scrub, :scrub!, :rindex, :downcase, :upcase, :empty?, :eql?, :setbyte, :upcase!, :capitalize, :swapcase, :dump, :downcase!, :capitalize!, :swapcase!, :hex, :oct, :split, :codepoints, :bytes, :chars, :concat, :lines, :reverse!, :<<, :freeze, :inspect, :ord, :start_with?, :prepend, :crypt, :reverse, :rjust, :intern, :scan, :ljust, :chop, :length, :size, :gsub, :succ, :chomp, :gsub!, :sub, :end_with?, :sub!, :lstrip!, :rstrip, :delete, :rstrip!, :chop!, :to_str, :to_sym, :center, :tr!, :tr, :tr_s, :to_s, :to_i, :lstrip, :tr_s!, :delete!, :squeeze!, :each_line, :chomp!, :strip!, :strip, :slice, :slice!, :rpartition, :each_byte, :to_f, :each_codepoint, :valid_encoding?, :ascii_only?, :encoding, :force_encoding, :each_char, :squeeze, :encode, :encode!, :hash, :b, :to_r, :<, :>, :<=, :>=, :between?, :clamp, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :public_send, :public_method, :singleton_method, :instance_variable_defined?, :define_singleton_method, :method, :instance_variable_set, :extend, :to_enum, :enum_for, :!~, :respond_to?, :object_id, :send, :display, :nil?, :class, :singleton_class, :clone, :dup, :itself, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variable_get, :instance_variables, :!, :!=, :__send__, :equal?, :instance_eval, :instance_exec, :__id__]
Side note, the methods
method is actually a method on the Object class, that our example_object
has because it is an instance of the String class, and the String class inherits from the Object class. You can see it in the above list as one of the methods available in our object.
This means our object can receive any of the messages listed above, and when it does receive them it will execute the correspondingly named method, if one exists.
Conclusion
You can send any message to any object using the dot notation (but doesn’t mean that it will work).
When you send a message to an object, and that object has the corresponding method as a public interface, then that message will call the method on the object.