Interesting Scoping Rules

val = "fem"
class Test
puts val
end

or

class Test
val = "A"
def info
puts val
end
end

Test.new.info

or

val = 1
def t
puts val
end
t

Why is it none of these are allowed? All of these seem like perfectly
logical places that lexical scoping would allow. It really suprised me
that none of thse work, anyone have an explanation for this behavior?

Charles Comstock

Hi --

val = "fem"
class Test
   puts val
end

# or

class Test
   val = "A"
   def info
  puts val
   end
end

Test.new.info

# or

val = 1
def t
  puts val
end
t

Why is it none of these are allowed? All of these seem like perfectly
logical places that lexical scoping would allow. It really suprised me
that none of thse work, anyone have an explanation for this behavior?

My explanation is kind of circular, I guess: those variables are out
of scope because def starts a new scope :slight_smile: I'm so used to it I don't
really notice it. I don't have any real technical insight into why
it's that way.

But I just wanted to add... don't forget you can use #define_method if
you want to keep the same scope:

  class A
    a = 1
    define_method("b", lambda { puts a })
  end

  A.new.b # 1

David

···

On Wed, 14 Apr 2004, Charles Comstock wrote:

--
David A. Black
dblack@wobblini.net

Take this with a pinch of salt, I am on my first cup of caffeine

  • I’m sure I’ll get corrected if it’s glaringly wrong. (I hope so)

val = “fem”

This defines a local variable called ‘val’ on Object

  • not the same as an instance variable.

class Test
puts val
end

Test can’t see the local variable on Object, you get an error like:

in t': undefined local variable or method val’ for #Object:0x807bcd8 (NameError)
from aaa:5

So you’d need an accessor on Object to get to it, and even then I think it’s gone
out of scope.
(This of course won’t print anything until you call Test.new either).

this works:

class Test
val = “fem”
puts val
end
Test.new

or

class Test
val = “A”

def info
puts val
end
end

Test.new.info

you can’t see val here because it’s not an instance variable of Test
objects, it’s a local variable of the Class Test. Even if you make it an
instance variable, and call it directly then
you have problems, because there is no accessor method defined:

rasputin@lb:tmp$ cat bbb.rb
class Test
@val = “A”
def info
puts Test.val
end
end
Test.new.info
rasputin@lb:tmp$ ruby -w bbb.rb
bbb.rb:4:in info': undefined method val’ for Test:Class (NameError)
from bbb.rb:7

or

val = 1
def t
puts val
end
t

I think this is because val is a local variable, not an instance variable of
Object. Again, it’s gone out of scope by the time you call t().
If you replace val with @val, it prints ‘1’, which is what you’d probably expect.

···

Why is it none of these are allowed? All of these seem like perfectly
logical places that lexical scoping would allow. It really suprised me
that none of thse work, anyone have an explanation for this behavior?


Rasputin :: Jack of All Trades - Master of Nuns

Dick Davies wrote:

Take this with a pinch of salt, I am on my first cup of caffeine

  • I’m sure I’ll get corrected if it’s glaringly wrong. (I hope so)

val = “fem”

This defines a local variable called ‘val’ on Object

  • not the same as an instance variable.

class Test
puts val
end

Test can’t see the local variable on Object, you get an error like:

in t': undefined local variable or method val’ for #Object:0x807bcd8 (NameError)
from aaa:5

So you’d need an accessor on Object to get to it, and even then I think it’s gone
out of scope.
(This of course won’t print anything until you call Test.new either).

It’s not so much that it hasn’t gone out of scope here, so much as it is
no longer accessable from the inner scope. If I use val further on
after the class def it will work perfectly fine.

this works:

class Test
val = “fem”
puts val
end
Test.new

or

class Test
val = “A”

def info
puts val
end
end

Test.new.info

you can’t see val here because it’s not an instance variable of Test
objects, it’s a local variable of the Class Test. Even if you make it an
instance variable, and call it directly then
you have problems, because there is no accessor method defined:

rasputin@lb:tmp$ cat bbb.rb
class Test
@val = “A”
def info
puts Test.val
end
end
Test.new.info
rasputin@lb:tmp$ ruby -w bbb.rb
bbb.rb:4:in info': undefined method val’ for Test:Class (NameError)
from bbb.rb:7

or

val = 1
def t
puts val
end
t

I think this is because val is a local variable, not an instance variable of
Object. Again, it’s gone out of scope by the time you call t().
If you replace val with @val, it prints ‘1’, which is what you’d probably expect.

Why is it none of these are allowed? All of these seem like perfectly
logical places that lexical scoping would allow. It really suprised me
that none of thse work, anyone have an explanation for this behavior?

I guess I should have qualified my statement a little better, I did
recognize that a def seems to be a hard scoping boundary, the question
was much more that I was very suprised by this, and was curious if
anyone had any insight as to WHY ruby chose to work things like this?

It suprises me much in the same way that we cannot def inside a def, it
will result in a new def at the top scope. It also suprises me in the
way that if we stick a class inside of a class instance variables will
not bubble down into the inner class.

Was this all just a sorta clever way to avoid needing to back check up
all scopes each time a variable is used?

It just goes against my general programming language intuition, it feels
singularly un-schemeish in a place I expected it to act scheme-ish, let
alone java-ish, c++ish and most other programming languages I can think
of. I’m sure I’ll get over it as it does most other things the way I
like, but it quite suprised me.

Charles Comstock

Hi --

I guess I should have qualified my statement a little better, I did
recognize that a def seems to be a hard scoping boundary, the question
was much more that I was very suprised by this, and was curious if
anyone had any insight as to WHY ruby chose to work things like this?

I think it's generally true that local variable scope changes every
time a new 'self' takes over:

  class X
    # self is X
    def blah
      # self is any instance of X
    end
    # self is X again, back to where we were
  end

  class X
    # self is X but we've backed out of the class and
    # come back in, so we have a new local scope
  end

The design is flexible: you can use #define_method instead of def, if
you want to avoid changing self and therefore starting a new local
scope.

It suprises me much in the same way that we cannot def inside a def, it
will result in a new def at the top scope. It also suprises me in the
way that if we stick a class inside of a class instance variables will
not bubble down into the inner class.

I'm not sure what you mean by that last one -- can you illustrate?

David

···

On Thu, 15 Apr 2004, Charles Comstock wrote:

--
David A. Black
dblack@wobblini.net

David A. Black wrote:

Hi –

I guess I should have qualified my statement a little better, I did
recognize that a def seems to be a hard scoping boundary, the question
was much more that I was very suprised by this, and was curious if
anyone had any insight as to WHY ruby chose to work things like this?

I think it’s generally true that local variable scope changes every
time a new ‘self’ takes over:

class X
# self is X
def blah
# self is any instance of X
end
# self is X again, back to where we were
end

class X
# self is X but we’ve backed out of the class and
# come back in, so we have a new local scope
end

The design is flexible: you can use #define_method instead of def, if
you want to avoid changing self and therefore starting a new local
scope.

It suprises me much in the same way that we cannot def inside a def, it
will result in a new def at the top scope. It also suprises me in the
way that if we stick a class inside of a class instance variables will
not bubble down into the inner class.

I’m not sure what you mean by that last one – can you illustrate?

David

class A
var = “me”
class B
puts var
end
end

It’s essentially the same rule that causes

var = “me”
class B
puts var
end

alone not to work I suppose. The other complaint was that

def a
def b
puts “a”
end
end

b

will result in
“a”

as opposed to getting a name error on b

also curious is that

class A
@a = “me”
class B
puts @a
end
end

results in
nil

again class appears to be a much harder scoping boundary
then I expected. Or rather that class b is really class A::B
and as such has no knowledge of ancestory to A.

class A
@a = “me”
class B
def t
puts @a
end
end
end

this is suggested by this returning nil.

Charles Comstock

···

On Thu, 15 Apr 2004, Charles Comstock wrote:
A::B.new.t

also curious is that

try this :slight_smile:

class A
   @a = "me"
   class B
     puts @a
   end
end

   class A
      C = "C"
      class B
         puts C
      end
   end

Guy Decoux

This example, at least, makes sense to me.

class A
@a = “me” # self is the Class object A
class B
puts @a # self is the class object A::B
end
end

Instance variables are local to the object, and A and A::B aren’t the same
object, so why should A::B see the instance variables of A? Similarly:

class A
@a = “me” # self is the Class object A
class B
@a = “me2” # self is the Class object A::B
def t
puts @a # self is an instance of A::B
end
end
end

All of those @a’s belong to different objects, so it’s not so surprising that
they aren’t all the same variable. I could see how this would be a little
confusing thinking from a Java inner-class perspective, but instance
variables in Ruby are object based rather than lexically based.

  • Dan
···

On Wednesday 14 April 2004 1:09 pm, Charles Comstock wrote:

also curious is that

class A
@a = “me”
class B
puts @a
end
end

results in
nil

again class appears to be a much harder scoping boundary
then I expected. Or rather that class b is really class A::B
and as such has no knowledge of ancestory to A.

class A
@a = “me”
class B
def t
puts @a
end
end
end

A::B.new.t

this is suggested by this returning nil.

ts wrote:

“C” == Charles Comstock cc1@cec.wustl.edu writes:

also curious is that

try this :slight_smile:

class A
@a = “me”
class B
puts @a
end
end

class A
C = “C”
class B
puts C
end
end

Guy Decoux

Right but the whole reasoning for doing something like that would be to
effect it later. This is wrong though in my opinion, if local vars get
lost in a change of class/def then why should constants go through these
barriers. Anyone else have thoughts on this?

Charlie

This example, at least, makes sense to me.

class A
@a = “me” # self is the Class object A
class B
puts @a # self is the class object A::B
end
end

Instance variables are local to the object, and A and A::B aren’t the same
object, so why should A::B see the instance variables of A? Similarly:

class A
@a = “me” # self is the Class object A
class B
@a = “me2” # self is the Class object A::B
def t
puts @a # self is an instance of A::B
end
end
end

All of those @a’s belong to different objects, so it’s not so surprising that
they aren’t all the same variable. I could see how this would be a little
confusing thinking from a Java inner-class perspective, but instance
variables in Ruby are object based rather than lexically based.

Can I just throw in a link to http://www.visibleworkings.com/little-ruby/

  • if I’d read Chapter 2 this morning instead of this afternoon, I wouldn’t
    have been so vague…
···


If life is a stage, I want some better lighting.
Rasputin :: Jack of All Trades - Master of Nuns