By Mladen Jablanović


2010-04-08 18:06:53 8 Comments

Inspired by this discussion, after some googling I wasn't able to find an answer to a pretty simple question regarding methods in Ruby: are methods objects or not?

There are different opinions here and there, and I would really like to hear, let's say, an in-depth explanation.

I'm aware of Object#method method, which takes a method name and returns a Method instance, but, on the other hand, there's a similar thing you can do with blocks to make them into Proc instances, and blocks aren't objects, so what makes methods any different?

6 comments

@JRL 2010-04-08 18:33:59

Methods are a fundamental part of Ruby's syntax, but they are not values that Ruby programs can operate on. That is, Ruby's methods are not objects in the way that strings, numbers, and arrays are. It is possible, however, to obtain a Method object that represents a given method, and we can invoke methods indirectly through Method objects.

From The Ruby Programming Language:
alt text

@Harshal_m_joshi 2012-07-28 07:55:45

Hi, If methods are not object then how it possible? irb(main):015:0> def hi irb(main):016:1> "hello" irb(main):017:1> end => nil irb(main):018:0> hi.object_id => 22452528 irb(main):019:0> hi.object_id.send hi => "hi" irb(main):020:0> hi.object_id.send(hi) => "hi"

@Mladen Jablanović 2012-07-29 14:48:56

hi.object_id first calls method hi, and then returns the object_id of its result (which is string "hello").

@Huliax 2019-02-15 16:50:37

In Ruby, methods are not objects. This is confusing because there is a Method class and you can get instances of Method. These instances are just proxies for the method itself. These instances provide some useful functionality. They have some internal magic that hooks them up to the actual method (so you can do things like Method#call) but you can't actually access that stuff (AFAIK).

1.method(:to_s).object_id == 1.method(:to_s).object_id #=> false

This means either that 1 has two #to_s methods (which it does not) or that what is returned by the method #method is not actually the method itself but some proxy for the method. If methods were actually objects then you would have situations where you were able to get the same instance twice. If methods were objects then you would be able to do things like set an instance variable on them and them, later, get the value of that instance variable after a second retrieval of the method object. You can't do that. So, while it may generally make no difference, there are situations where I find I am unable to do things that I would like to.

1.method(:to_s).instance_variable_set(:@foo, 'foo') #=> "foo" 
1.method(:to_s).instance_variable_get(:@foo)        #=> nil 
# And just in case you question it...
1.object_id == 1.object_id                          #=> true 

@yfeldblum 2010-04-08 18:27:40

In Ruby, methods and blocks are not, in and of themselves, native or first-class objects. However, they can very easily be wrapped in objects, such that it generally makes no difference.

But try out, and keep in mind the result of,

a = Object.method(:new).object_id
b = Object.method(:new).object_id
a == b
=> false

In Haskell, all values (including numbers as well as lambdas and functions) are first-class values. In every aspect of the language, they are all treated equivalently. This is not the case in Ruby, but it can be approximated.

@Tim Snowhite 2010-04-08 18:32:10

Justice, your argument was the same as mine. In addition, I'm not aware of any other way to return methods, so #method(method_name) seems to be the only way to reference a method at all, aside from calling it by name on it's original object.

@Marc-André Lafortune 2010-04-08 18:43:04

The only thing that your object_id proves is that they are not immediates. a = 1.0.object_id; b = 1.0.object_id; a == b # => false

@Andrew 2015-01-14 02:35:17

Because parenthesis are optional in ruby, method objects are generally "hidden" in the sense you need to explicitly fetch the method object via the method method. However if you make the effort to capture a method object it becomes quite clear that it acts like an object. Since Ruby >= 2.1 this is easier to take advantage of than ever.

For example, you can get your methods to behave more like they do in Javascript (where no parens is the method object and parens are used to call the method) like so:

foo = method def foo
  def a(num)
    3 * num.to_i
  end

  n = yield if block_given?
  a(n || 3)
rescue
  "oops!"
end

def foo.bar(num)
  a(num)
end

foo.class #=> Method
foo() #=> 9
foo.call #=> 9
foo.call{2} #=> 6
foo(){2} #=> 6
foo.call{ raise "blam!" } #=> "oops!"
foo.bar(5) #=> 15

See this gist for a version with these example written as tests.

JRL's answer quotes Matz book saying that methods are not objects like strings etc. are, but method objects are real, and other than the parens/no-parens thing they act pretty much like any other ruby object. It's a duck-typed language, so I'd say that qualifies methods as objects in my book.

@bvrwoo_3376 2012-03-17 14:25:03

Objects and Methods are not the same even if the return value for the methods is an object and not nil. Objects live on the heap unless in a method, lambda, or proc scope and the method itself lives on the stack and has an address assign after interpretation while static and class objects are allocated on the heap. Ruby still uses C to interpret it and pass it to the VALUE struct.

@simonmenke 2012-10-29 10:11:40

From ruby's perspective Methods are Objects. The implementation details are not important. A method can be addresses and passed just like any other object. Procs are also Objects (and blocks are just a syntactic way of creating a Proc/lambda).

@Jörg W Mittag 2010-04-08 19:38:33

You can't really tell.

The only way to get access to a method is to send the #method message to some object, which will then return a Method object. But is that Method object the method itself? Or is it a wrapper around the method? Or is it a converted version of the original method?

You can't know: if you want to look at a method, you have to call #method, at which point you definitely will get an object. What it was before you called #method you can't look at, therefore you can't tell.

A couple of datapoints: in Ruby, everything returns a value. What does def return? It always returns nil, not a Method object. And define_method? It returns a Proc, but not a Method (nor an UnboundMethod). [Note: in Rubinius, def returns the compiled bytecode of the method, but still not a Method object.]

If you look at the 4th and 5th paragraphs of Section 6.1 of the Ruby Language Specification (lines 29-34 and 1-5 on pages 5 and 6), you can clearly see that there is a distinction drawn between methods and objects. And if you look at the specification of the builtin classes, you will find that neither Method nor UnboundMethod are in there, nor is Object#method. IOW: you can build a perfectly standards-compliant Ruby interpreter in which methods aren't objects.

Now, blocks OTOH definitely aren't objects. There are many ways to construct Proc objects from blocks, which then have the same behavior as the original block (lambda, proc, Proc.new, the & sigil), but blocks themselves aren't objects.

Think about it this way: you can pass a string to File.new to construct a file object, but that doesn't make a string a file. You can pass a block to Proc.new to construct a proc object, but that doesn't make a block a proc.

@Mladen Jablanović 2010-11-28 09:07:09

Just for the reference: stackoverflow.com/questions/4294485/…

@Andrew Grimm 2012-03-19 22:08:52

Not wanting to sound sarcastic, but what is a block? Is it merely a piece of text in a .rb file?

@Powers 2014-05-22 01:42:55

Jörg clarified that Ruby methods are not objects in a later StackOverflow question @MladenJablanović links to. Here's the quote: "Note, however, that both the Method and the UnboundMethod are wrappers around the method, not the method itself. Methods are not objects in Ruby. (Contrary to what I have written in other answers, BTW. I really need to go back and fix those.)"

@rightfold 2015-12-24 13:11:01

@AndrewGrimm Blocks are blocks. They are a distinct entity that can only be acted on in certain ways.

Related Questions

Sponsored Content

28 Answered Questions

[SOLVED] Iterate through object properties

40 Answered Questions

[SOLVED] Check if a value is an object in JavaScript

24 Answered Questions

[SOLVED] How to write a switch statement in Ruby

20 Answered Questions

[SOLVED] Checking if a key exists in a JavaScript object?

  • 2009-07-08 13:21:32
  • Adam Ernst
  • 1798755 View
  • 2733 Score
  • 20 Answer
  • Tags:   javascript object

42 Answered Questions

[SOLVED] Detecting an undefined object property

19 Answered Questions

[SOLVED] What is attr_accessor in Ruby?

  • 2010-12-06 21:07:06
  • dennismonsewicz
  • 446434 View
  • 987 Score
  • 19 Answer
  • Tags:   ruby

31 Answered Questions

[SOLVED] What's the difference between a method and a function?

69 Answered Questions

[SOLVED] What is the most efficient way to deep clone an object in JavaScript?

32 Answered Questions

[SOLVED] Find object by id in an array of JavaScript objects

25 Answered Questions

[SOLVED] Check if a value exists in an array in Ruby

  • 2009-12-31 17:49:03
  • user211662
  • 811128 View
  • 1254 Score
  • 25 Answer
  • Tags:   ruby arrays

Sponsored Content