Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 807
Ellery Temple Avatar asked Jan 17 '16 23:01

Ellery Temple


People also ask

What is binding in Ruby?

To keep track of the current scope, Ruby uses bindings, which encapsulate the execution context at each position in the code. The binding method returns a Binding object which describes the bindings at the current position.

What is a Ruby method?

A method in Ruby is a set of expressions that returns a value. With methods, one can organize their code into subroutines that can be easily invoked from other areas of their program. Other languages sometimes refer to this as a function. A method may be defined as a part of a class or separately.


1 Answers

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.

like image 66
sawa Avatar answered Sep 28 '22 20:09

sawa