7

In Ruby, everything is supposed to be an object. But I have a big problem to get to the function object defined the usual way, like

def f
    "foo"
end

Unlike in Python, f is the function result, not the function itself. Therefore, f(), f, ObjectSpace.f are all "foo". Also f.methods returns just string method list.

How do I access the function object itself?

5
  • This is one of (many) things that drives me berserk in ruby. You can't refer to a function by name without invoking it. I have arguments about this with my cow orkers. Commented Dec 19, 2009 at 16:55
  • I think that Ruby has its own way and some principles used in other languages simply do not apply (in this case I'd probably define the function with Proc, or use code block), but I still wonder if there is a positive answer to my question Commented Dec 19, 2009 at 17:02
  • 1
    @Jonathan: You can refer to a method's name without calling it. A method's name is a symbol. So the name of this method is :f. Ruby is pretty famous for its metaprogramming capabilities, and method names are used all the time there. Commented Dec 20, 2009 at 7:48
  • @Chuck Symbols aren't coupled with functions at all, they are just lightweight string objects (they only have a small subset of the methods) that are used instead of constants. Wherever you can pass a symbol as a method name, you can pass a string instead if you want. Commented Dec 20, 2009 at 12:11
  • @dvyjones: I did not say they are coupled with methods. I said they can be used to refer to a method's name, in response to Jonathan's claim that "you can't refer to a method by name." In fact, it would be impossible for a method's name to be coupled with it, since many methods can share the same name. Commented Dec 20, 2009 at 19:12

7 Answers 7

10

You simply use the method method. This will return the Method instance that matches with that method. Some examples:

>> def f
>>   "foo"
>> end
=> nil
>> f
=> "foo"
>> method(:f)
=> #<Method: Object#f>
>> method(:f).methods
=> [:==, :eql?, :hash, :clone, :call, :[], ...]
>> class SomeClass
>>   def f
>>     "bar"
>>   end
>> end
=> nil
>> obj = SomeClass.new
=> #<SomeClass:0x00000001ef3b30>
>> obj.method(:f)
=> #<Method: SomeClass#f>
>> obj.method(:f).methods
=> [:==, :eql?, :hash, :clone, :call, :[], ...]

Hope this helps.

Sign up to request clarification or add additional context in comments.

1 Comment

Oh, and the Method object is a Proc-like object, so you doo obj.method(:f).call() or obj.method(:f)[] to call it. Or, on Ruby 1.9.1; obj.method(:f).().
3

The method method will give you a Method object

f = obj.method :f
puts f.call # or f[]

this f is bound to obj. You can also get an unbound method:

unbound_plus = Fixnum.instance_method('+')
plus_2 = unbound_plus.bind(2)

(There is also a unbind method)

3 Comments

so you'd say that my f is unbound method. it looks reasonable. however, the fact that my f als act as ObjectSpace methods (which otherwise return the objects) is confusing
well, it still does not answer my question, how do I treat my f as Method instance
@mykhal: Any method you define at the top level becomes an instance method of Object, so ObjectSpace (which is an object, just like everything else in the language) gets the method too. You shouldn't normally be able to call it from outside of ObjectSpace, though — methods defined that way default to being private.
3

well I have found the answer myself

obj = method :f

thank you all for the inspiration :)

2 Comments

This gives you the method, but not a pure function. Creating a Proc object is maybe closer to what you want. A method always requires a receiver, since it is bound to an object, a proc(edure) is an object by itself and can thus just be called like a function.
@Adrian it gives unbound method. try yourself: ruby -e 'def f; "foo"; end; obj = method :f; puts obj.call'
1

In Ruby, what you are asking for does not make sense. (It makes sense in languages like Python, JavaScript, Java, and C#.)

In Ruby, you can tell a class what messages it should respond to and in what ways it should respond to those messages. The most common way to tell a class that is to define a method in the class. But again, that simply means: when someone sends the message f to this instance, here's the behavior that the instance should respond with. There is no function object.

You can do things like get a symbol (method_name = :foo) and get a closure (method = proc { obj.foo }).

3 Comments

if f is not an object, why is it in ObjectSpace then?
Methods are objects. They're just not objects the runtime allows you to access WHILE they're still being defined. If you want to do that then stick to Python.
Actually, there is a Method class that all methods are an instance of. When you do obj.some_method in Ruby, it sends the message to obj, which looks in it's method list for a matching method, and then calls that method. If it can't find the method, it calls method_missing.
1

That isn't a function; it's a method of an object. If you want to get an object representing a method, you ask the owning object for it:

someobj.method :f

For example:

plus_one = 1.method :+
plus_one[9] # 10

2 Comments

def f; "foo"; end is really not a function?
Conceptually, no — it's a method. It's inherently bound to an owner in Ruby. The closest Ruby equivalent to true functions would be Procs.
0

You can obtain an object that will correspond to that function at runtime, but as far as I know there's no equivalent to what Python allows you to do right there in the function/class definition.

Hopefully someone will prove me wrong, but I've never been able to pull it off.

Comments

0

You should create a Proc object if you want a function object

f = Proc.new { |x| x * 2 }

you call the function using either

f.call(8) # => 16

or

f[8] # => 16

you may even use this function object in a map operation

[1, 2, 3, 4, 5].map(&f) # => [2, 4, 6, 8, 10]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.