Alternatives to Lexical Binding with Ruby
January 6th, 2008 by proj
In ruby the default way to get a name to return a value is via ruby’s lexical scoping rules. Lexical scoping rules use the way the code is written to determine what a variable name means. You can read the code and understand what a variable will mean when a certain piece of code runs. The alternative to lexical binding is dynamic binding. Dynamic binding determines the value of a variable by the process executing the code. Dynamic binding has a potential to be more confusing because code written this way could have a variety of meanings depending on how the code is executed. Old versions of lisp used dynamic binding by default. In common lisp lexical binding is the default but it is still possible to make a variable dynamically bound.
There are certain scenarios where dynamic binding is particularly useful. It allows the caller to directly control the callee without using any intermediate objects, instead only using the underlying call chain. Certain forms of generic programming become very easy with dynamic binding.
Consider the following as an illustration of implicit dynamic binding:
def print_list(a_list)
puts a_list.join(separator or ', ')
end
print_list([1, 2, 3]) # -> 1, 2, 3
separator = ' '
print_list([1, 2, 3]) # -> 1 2 3
The simple example above also illustrates how implicit dynamic binding in a programming language can really start to dirty up a perfectly good code base. An unfortunate misspelling would be hard to debug in such a language. Additionally various rules about encapsulation are broken along the way.
The dynamic binding style still does have it uses however, especially in a language that supports functional abstraction. In ruby it is possible to define your own function objects and pass them around easily.
my_lambda = lambda {|x| puts x + 10 }
my_lambda.call(1) # -> 11
my_lambda.call(2) # -> 12
The lambda method in Kernel#lambda returns a new Proc that wraps the code in the block ‘{}’.
In some cases it could be useful to define a dynamically bound lambda that defines actor behavior in a generic way.
def execute_all(actor_list, proc)
actor_list.each {|actor| actor.execute(proc) }
end
execute_all(lambda {play_anim(anim_family, 'walk', speed) }
The details of the lambda are open to the interpretation of the actor at the time the code runs. I’m not of the opinion that this is the best way to write this code but it certainly wins in brevity and in being fairly generic. There are better examples of using dynamic binding in the common lisp system.
To contrast dynamic binding here is an example of lexical binding. The lambda defined here binds a_var at the point the lambda is written, not where it is run (hence lexical scoping). This create a lexical closure which closes over the definition of a_var to keep it around later. The value returned below is 1 although at the time the code runs there is a binding for a_var that changes it’s meaning to 2.
def foo(p)
a_var = 2
puts p.call
end
a_var = 1
foo(lambda { a_var }) # -> 1
If ruby used dynamic binding by default the output of the code snipped above would be 2. To resolve a dynamically bound variable you walk up the chain of current activation records to find the nearest variable binding. In ruby the lexical variable binding captures a lot, including the current ’self’, block iterator, and locals.
Now that I’ve covered all that I can talk about ruby tools for working with the bindings and different ways to program with a more dynamic mode.
In ruby it is possible to access the binding from code. The kernel method binding offers the caller access to an opaque Binding object. Currently the only way to use this binding object that I have found is via eval().
def foo()
a = 1
return binding
end
b = foo()
eval('puts a', b) # -> 1
The binding is manually captured here and passed into eval. This is a form of explicit dynamic binding. The only drawback of this method is that it doesn’t work for forms that have already been evaluated.
Explicit run-time variable binding is a pretty common software pattern. The alternative that is often used in C++ or Java is to create a special context object which is passed as a parameter to a method. The context is a way of explicitly controlling the binding. You create a custom mapping object (a hash for example) and pass it around to create your own variable binding. Here’s an example:
def foo(ctx, proc)
puts proc.call() # -> 1
ctx[:x] = 2
puts proc.call() # -> 2
end
ctx = {:x=>1}
foo(ctx, lambda {|ctx| ctx[:x] })
Wouldn’t it be nice if we could encapsulate this pattern without requiring the extra parameter, dictionary mapping and extra indirection of having to make all variable access through the mapping?
I haven’t looked at the C code changes that would be required to ruby to do this but I think it’s possible to roll this pattern of coding directly into the ruby built-in library.
The additions are Binding#from_hash(aHash), Proc#call_with_binding(aBinding).
def let(k, &block)
block.call_with_binding(Binding.from_hash(k))
end
let('a_var'=>1) {
puts a_var
} # -> 1
dynamic_bound = lambda {
puts a_var
}
a_var = 1
dynamic_bound.call_with_binding(binding) # -> 1
a_var = 2
dynamic_bound.call_with_binding(binding) # -> 2
The above code is a hypothetical approach. One that might be interesting to implement. There is one more alternative to lexical binding in ruby that I discovered after I had initially written this post. It relies directly or indirectly on the usage of instance_eval. Here’s a simple example:
class Foo
def initialize(a) @a = a end
end
f = Foo.new(1)
f.class.send(:define_method, :foo, lambda { puts @a })
f.foo # -> 1
f2 = Foo.new(2)
f2.foo # -> 2
The method :define_method defines the proc in terms of Foo. The @a binds to the meaning of @a in the context of an instance of Foo.
A less permanent way to do this is to use instance_eval directly:
f.instance_eval { @a = @a + 10 }
Related posts:






