In python, it’s fairly straightforward to reference a function:
>>> def foo():
... print "foo called"
... return 1
...
>>> x = foo
>>> foo()
foo called
1
>>> x()
foo called
1
>>> x
<function foo at 0x1004ba5f0>
>>> foo
<function foo at 0x1004ba5f0>
However, it seems to be different in Ruby since a naked foo actually calls foo:
ruby-1.9.2-p0 > def foo
ruby-1.9.2-p0 ?> print "foo called"
ruby-1.9.2-p0 ?> 1
ruby-1.9.2-p0 ?> end
=> nil
ruby-1.9.2-p0 > x = foo
foo called => 1
ruby-1.9.2-p0 > foo
foo called => 1
ruby-1.9.2-p0 > x
=> 1
How do I actually assign the function foo to x and then call it? Or is there a more idiomatic way to do this?
Ruby doesn’t have functions. It only has methods (which aren’t first-class) and
Procs which are first-class, but are not associated with any object.So, this is a method:
Oh, and, yes, this is a real method, not a top-level function or procedure or something. Methods defined at the top-level end up as private(!) instance methods in the
Objectclass:This is a
Proc:Notice that
Procs are called differently from methods:The
foo.(bar)syntax is just syntactic sugar forfoo.call(bar)(which forProcs andMethods is also aliased tofoo[bar]). Implementing acallmethod on your object and then calling it with.()is the closest thing you will get to Python’s__call__ables.Note that an important distinction between Ruby
Procs and Python lambdas is that there are no restrictions: in Python, a lambda can only contain a single statement, but Ruby doesn’t have the distinction between statements and expressions (everything is an expression), and so this limitation simply doesn’t exist, therefore in a lot of cases where you need to pass a named function as an argument in Python because you cannot express the logic in a single statement, you would in Ruby simply pass aProcor a block instead, so that the problem of the ugly syntax for referencing methods doesn’t even arise.You can wrap a method in a
Methodobject (which essentially duck-typesProc) by calling theObject#methodmethod on an object (which will give you aMethodwhoseselfis bound to that particular object):You can also use one of the methods in the
Module#instance_methodfamily to get anUnboundMethodfrom a module (or class, obviously, since a class is-a module), which you can thenUnboundMethod#bindto a particular object and call. (I think Python has the same concepts, albeit with a different implementation: an unbound method simply takes the self argument explicitly, just like the way it is declared.)Note that you can only bind an
UnboundMethodto an object which is an instance of the module you took the method from. You cannot useUnboundMethodsto “transplant” behavior between unrelated modules:Note, however, that both the
Methodand theUnboundMethodare 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.) You can wrap them in objects, but they aren’t objects, and you can see that because you essentially get all the same problems you always get with wrappers: identity and state. If you callmethodmultiple times for the same method, you will get a differentMethodobject every time. If you try to store some state on thatMethodobject (such as Python-style__doc__strings, for example), that state will be private to that particular instance, and if you try to retrieve your docstring again viamethod, you will find that it is gone.There is also syntactic sugar in the form of the method reference operator
.::Which is identical to