In Ruby, you can use a block as though it were a binding:
def foo(&b)
eval 'puts a', b
end
def bar
a = 1
foo {} # prints out '1'
end
It is largely because of this feature that our block scoping is very
costly; whenever a block is present, the containing method's local
variables must all be lifted to the heap, so they can be accessed
across calls. This means that 'bar' above will have a permanent
performance penalty for all local variables, even though none of them
are accessed within the block passed to 'foo'.
In Groovy, there's no ability to use a block as a binding, so they
only close over the variables that will actually be accessed. This
means that you only pay the heap-scoping cost for variables you
explicitly use across the closure boundary. This allows Groovy's
closures to be considerably lighter-weight, and in many cases be as
fast as any other call.
But there is a way out of this. Yehuda and I talked a bit about it and
realized that if we could inspect the target method whenever we're
calling a block, we could determine whether a full heap scope would be
needed. There are only three constructs that would trigger this
potential:
* A block argument (&arg) in the parameter list, because it's
capturing the block for later use
* A zsuper call (no-arg, no-parens super), because that call could
capture the block for later use
* If the call itself is Proc.new, proc, or lambda, because it's
capturing the block (or -> in 1.9)
* Any eval-like call (binding, eval)
All three of these are inspectable at method-construction time, so we
could have a flag on method objects for "might do evil things with
your block". At that point, we could lazily lift all our local
variables to a heap structure and follow the heap-scoping path from
then on, This would have to be a hard trap + branch to deoptimized
code, but it could work. We will need to think about how to deoptimize
by branching to a new body of codewith current execution state, but I
think it's possible.
An alternative to dynamic deopt would be to add profiling information
at the call site indicating whether we ever see a block used as a
binding. We would still need to consider a deopt mechanism, but we
would not necessarily need to depend on it as much, due to the
profiling probably being all the information we need.
I would strongly prefer this feature just disappear, but it's not going to.
- Charlie
---------------------------------------------------------------------
To unsubscribe from this list, please visit:
http://xircles.codehaus.org/manage_email