Yuh-Ruey Chen
10/31/2008 6:34:00 PM
Thanks for the reply.
On Oct 31, 12:55 pm, "David A. Black" <dbl...@rubypal.com> wrote:
> > My questions are within the following example:
>
> > x = 10
>
> > def foo
> > # how to access x from here?
>
> > end
>
> > class Klass
> > # how to access x from here?
> > def bar
> > # how to access x from here?
> > end
> > end
>
> > lambda { x } # I can access x here but why not in foo or Klass or bar?
>
> I'm not sure what you mean by "why". Every language has scoping rules.
> Ruby's rules include provision for closures, in that code blocks do
> not start a new local scope and can be used as the bodies of anonymous
> function objects.
I understand that they create new scopes, but what I don't get is why
you can't access enclosing scopes! In most other languages, scopes are
hierarchical, in that nested scopes will include parent scopes.
JS:
var x = 10
function foo() {
x // I can still access x!
}
Python:
x = 10
def foo():
x # I can still access x!
Scheme:
(let ((x 10))
((lambda ()
x) ; I can still access x!
))
> There's no moral imperative, one way or the other. You're just
> encountering and learning how Ruby handles these things. Relax :-)
>
> > I sincerely hope I'm missing something here. To me, the inability to
> > access local variables in an enclosing scope is very counter-
> > intuitive. I thought Ruby was supposed to be elegant? At the very
> > least, I expect some sort of "nonlocal" statement similar to Python,
> > e.g.
>
> > def foo
> > nonlocal x
> > # I can access x in enclosing scope now
> > end
>
> I thought you said you wanted elegance :-)
I did explicitly say "at the very least". I'd rather not have to
specify that "nonlocal x", but if it were necessary for the sake of
compatibility, then so be it. And that's another issue: if Ruby
provides all these methods that allow me to break encapsulation, I
don't see why there isn't a method that allows me to access local vars
in enclosing scopes. That's just inflexible.
With that said, I kinda understand why x can't simply refer to
enclosing scopes, because it would be fragile: a method x would be
added which would make x refer to that method instead of the var in
the enclosing scope. That's why I think there needs to be some
equivalent of "nonlocal x". For a more slightly more elegant example:
def foo
$nonlocal.x
end
or
def foo
::x # don't know if this would conflict with anything
end
> > And no, I don't want to have to use global variables - that would just
> > be pollution and would be incredibly unwieldy in large projects.
> > Frankly, if there was a way to access local variables in enclosing
> > scopes, there wouldn't even need to be a special global variable
> > concept.
>
> Have you looked at class_eval and define_method?
>
> class MyClass; end
> m = "my_method"
> MyClass.class_eval do
> define_method(m) { puts "Hi from #{m}!" }
> end
>
> and similar.
Yes I'm familiar with them, and I actually would like to use them, but
blocks can't have default arguments. Ideally, I would like to write
everything with blocks and avoid all this magical "new scope"
nonsense. It makes metaprogramming tricky in my experience.