From: Bob Hutchison Date: 2005-10-02T04:14:50+09:00 Subject: Re: ideas for an RCR: variable locality On Oct 1, 2005, at 12:20 PM, Eric Mahurin wrote: > Problem: Within a method you can't reuse a variable name for a > local variable. Some changes in ruby 2 may help the issue, but > also hurt it in another way. > > Example: For performance reasons, I'm having my package > (grammar - generic parser), generate flattened (reduce > calls/stack depth) code. As long as each "method" (to be > flattened) is simple enough that it doesn't require local > variables I'm OK. But as soon one of these need a local > variable, I'm in trouble - that variable could step on the toes > of another including one just like it that it calls/flattens. > > Possible solutions: > > x = 0 > a,b = 1,2 > z = localize { |x,y| # doesn't modify outside x > x = a+b # use a and b from outside > y = a-b > x*y > } > > > Any opinions on the topic? Any other ideas? > > It seems that all of your suggests require a change to Ruby, so, keeping that in mind... Something like: x = 0 a,b = 1,2 z = { |x, y| x = a + b y = a - b x * y } would be my preference, but that would break existing code. So maybe something like: x = 0 a,b = 1,2 z = %M{ |x, y| x = a + b y = a - b x * y } (the letter in the %M doesn't matter, but that's the idea) I'll point out that this is a very similar problem to what languages with advanced macro capabilities (e.g. Common Lisp) have had to solve. The mechanism CL used is 'quasi-quote' with a syntactic abbreviation of '`' (a back quote). Inside quasi-quoted text if a ',' is encountered the value of that variable is substituted in. Anyway, so this got me thinking along those lines. This code works in Ruby right now... module Gensym @@gensym_count = 0 def Gensym.gensym(prefix="gensym") #generates a unique name with the given prefix @@gensym_count += 1 return sprintf("%s_%s", prefix, @@gensym_count) end end def compute_z_macro(x=Gensym.gensym, y=Gensym.gensym) return %Q{ #{x} = a + b #{y} = a - b #{x} * #{y} } end def go x = 0 a,b = 1,2 z = eval compute_z_macro printf("x = %d, z = %d\n", x, z) z = eval compute_z_macro("x") printf("x = %d, z = %d\n", x, z) puts compute_z_macro puts compute_z_macro("x") end go There are no local variables created when the eval is executed (this is very good) And with some changes to Ruby (defmacro, automatic call to gensym if no parameter value provided, using the ',' notation rather than #{}, % M, automatic call to eval when the 'call' of the macro happens, not- evaluating parameters to the macro) defmacro compute_z(x, y) return %M{ ,x = a + b ,y = a - b ,x * ,y } end def go x = 0 a,b = 1,2 z = compute_z printf("x = %d, z = %d\n", x, z) z = compute_z(x) printf("x = %d, z = %d\n", x, z) end Anyway, you have macros at the same time. A little far from what you were asking but... Cheers, Bob > > __________________________________________________ > Do You Yahoo!? > Tired of spam? Yahoo! Mail has the best spam protection around > http://mail.yahoo.com > > > ---- Bob Hutchison -- blogs at Recursive Design Inc. -- Raconteur --