Ellery Temple
Ellery Temple

Reputation: 147

What the purpose of bind/unbind methods in Ruby?

What is the purpose of having Method#unbind and UnboundMethod#bind?

From what I gather, methods are callable objects like procs and lambdas, except that methods are bound to the scope of their receiver:

class SomeClass
  def a_method; puts "from SomeClass"; end
end

s = SomeClass.new
s.a_method # => "from SomeClass"

I can call a_method if I'm within the context of SomeClass or if I have an object of SomeClass. I can make it a callable object by extracting the method as a Method object, yet it's still bound to an object of class SomeClass in this example:

m = s.method :a_method
m.class # => Method
m.owner # => SomeClass
m.call # => "from SomeClass"

Why would I want to unbind a method from its receiver? Maybe I can pass this around or bind it to a different object giving it new context, maybe I can have a completely different object call this method without inheritance, but I can't do anything with it unless I bind it to an object of its original class or I convert it to a Proc object (really a lambda, since methods and lambdas are somewhat similar):

# Module#instance_method gives me an UnboundMethod
ub = SomeClass.instance_method :a_method
ub.class # -> UnboundMethod

# now I can't make any calls 
ub.call # -> NoMethod Error, undefined method 'call'

class AnotherClass; end
a = AnotherClass.new
b = ub.bind(a) # -> TypeError: bind argument must be an instance of SomeClass
b = ub.bind(SomeClass.new).call # -> "from SomeClass"

I could convert the method object into a proc and maybe do something with it:

AnotherClass.class_eval do
  # I can access m becausec this block is evaluated in the same 
  # scope it's defined, so I can grab m ;)
  define_method(:method_from_some_class, m.to_proc)
end

AnotherClass.instance_methods(false) # -> [:method_from_some_class]
a.method_from_some_class # -> "from SomeClass"

What is the purpose of doing this? What are the real world applications for something like this?

Upvotes: 14

Views: 5632

Answers (1)

sawa
sawa

Reputation: 168101

It is indeed useful for metaprogramming. Suppose you want to know the location of the source code for SomeClass#method. If you can generate an instance of SomeClass, then you can create a (bound) method instance of it on that SomeClass instance, on which you can call various methods to investigate some meta-data of the method. But what if you did not know the method signature of SomeClass#new, or what if SomeClass's constructor method was named other than SomeClass#new? Just safely creating an instance of SomeClass can be difficult. That is where unbound method comes in handy. Without bothering with a particular instance of the class, or with how to create an instance, you can simply do SomeClass.instance_method(:a_method) (which is an unbound method), then call source_location on it to investigate the location of the definition:

unbound = SomeClass.instance_method(:a_method)
puts unbound.source_location

And when would this kind of metaprogramming be necessary in the real world applications? One example is when you are creating an IDE with functions for method lookup.

Upvotes: 15

Related Questions