Problem with constants

I'm puzzled:

···

-----------------------
class X
  A = 1
  def X.a
    A
  end
end

class Y < X
  A = 2
end

class Z < X
  A = 3
  def Z.a
    A
  end
end

p X.a #=> 1
p Y.a #=> 1
p Z.a #=> 3
-----------------------
(ruby 1.8.2 (2004-12-25) [i386-mswin32])

Shouldn't this yield at least a warning?
Is this a feature?

cheers

Simon

Kroeger Simon (ext) wrote:

I'm puzzled:
-----------------------
class X
A = 1
def X.a
   A
end
end

class Y < X
A = 2
end

class Z < X
A = 3
def Z.a
   A
end
end

p X.a #=> 1
p Y.a #=> 1
p Z.a #=> 3
-----------------------
(ruby 1.8.2 (2004-12-25) [i386-mswin32])

Shouldn't this yield at least a warning?
Is this a feature?

Since A is not a class variable (it's a local variable) it's saved in "X.a" closure. In Y class it doesn't exist, so it can't influence on "X.a" method.

PS I hope my crappy english doesn't mess things too much.

Kroeger Simon (ext) schrieb:

I'm puzzled:
-----------------------
class X
  A = 1
  def X.a
    A
  end
end

class Y < X
  A = 2
end

class Z < X
  A = 3
  def Z.a
    A
  end
end

p X.a #=> 1
p Y.a #=> 1
p Z.a #=> 3
-----------------------
(ruby 1.8.2 (2004-12-25) [i386-mswin32])

Shouldn't this yield at least a warning?
Is this a feature?

Yes. Constants are lexically scoped. As I've learned from a recent post here on ruby-talk, you can change your code to

   def X.a
     self::A
   end

to get the behavior I suppose you're looking for.

Regards,
Pit

Hi --

Kroeger Simon (ext) wrote:

I'm puzzled:
-----------------------
class X
A = 1
def X.a
   A
end
end

class Y < X
A = 2
end

class Z < X
A = 3
def Z.a
   A
end
end

p X.a #=> 1
p Y.a #=> 1
p Z.a #=> 3
-----------------------
(ruby 1.8.2 (2004-12-25) [i386-mswin32])

Shouldn't this yield at least a warning?
Is this a feature?

Since A is not a class variable (it's a local variable) it's saved in "X.a" closure. In Y class it doesn't exist, so it can't influence on "X.a" method.

Actually A is a constant, not a local variable, and method definitions
aren't closures. I'm pretty sure that what's happening is that the
constant references are being resolved at compile-time, so that by the time
Y.a is run, the reference inside X.a has been permanently resolved to
X::A.

See what happens when you make this change:

   def X.a
     const_get("A")
   end

Now the constant is being resolved dynamically, and you'll get 1/2/3
in the output.

David

···

On Wed, 21 Sep 2005, HaPK wrote:

--
David A. Black
dblack@wobblini.net

HaPK wrote:

Kroeger Simon (ext) wrote:

I'm puzzled:
-----------------------
class X
A = 1
def X.a
   A
end
end

class Y < X
A = 2
end

class Z < X
A = 3
def Z.a
   A
end
end

p X.a #=> 1
p Y.a #=> 1
p Z.a #=> 3
-----------------------
(ruby 1.8.2 (2004-12-25) [i386-mswin32])

Shouldn't this yield at least a warning?
Is this a feature?

Since A is not a class variable (it's a local variable) it's saved in "X.a" closure. In Y class it doesn't exist, so it can't influence on "X.a" method.

PS I hope my crappy english doesn't mess things too much.

Ooops... sorry.. Didn't get you right.

Indeed, seems like a bug with constants assignment.

class X
  A = 1
end

class Y < X
  A = 2
end

class Z < X
end

X.constants => 'A'
Y.constants => 'A'
Z.constants => 'A' # Z inherits constants from its parent

X::A = 3
Z::A => 3 # changes in superclass populated to subclasses

Z::A = 4
X::A => 3 # changes in subclass remains local to subclass

Seems like assignments are made without lookup in superclasses.

aren't closures. I'm pretty sure that what's happening is that the
constant references are being resolved at compile-time, so that by the time
Y.a is run, the reference inside X.a has been permanently resolved to
X::A.

Well not really : ruby *want* that you think that the constants are resolved
statically

[ruby-talk:32774]

"Those rules provide you the "illusion" of statically scoped constants."

Guy Decoux

Hi --

Indeed, seems like a bug with constants assignment.

class X
A = 1
end

class Y < X
A = 2
end

class Z < X
end

X.constants => 'A'
Y.constants => 'A'
Z.constants => 'A' # Z inherits constants from its parent

X::A = 3
Z::A => 3 # changes in superclass populated to subclasses

Z::A = 4
X::A => 3 # changes in subclass remains local to subclass

Seems like assignments are made without lookup in superclasses.

There's no bug. There's a lookup path for constants. Z finds X::A on
its lookup path. You could also do: Z::String and although you'd get
a warning, Ruby would indeed return the top-level constant String
(because there's no other String to replace it in the lookup path).

When you change X::A (aside from getting a warning :slight_smile: it's not
exactly that the change is propagated to Z. Rather, the change
affects a constant that is on Z's lookup path -- so, naturally, when Z
sees that constant, it's changed. It's not because Z is a subclass of
X. The change to X::A would be visible from anywhere.

When you assign to Z::A, you're creating a new constant. This has no
effect on X::A; the two are completely unrelated.

David

···

On Wed, 21 Sep 2005, HaPK wrote:

--
David A. Black
dblack@wobblini.net

David A. Black wrote:

[...] Actually A is a constant, not a local variable, and method definitions
aren't closures. I'm pretty sure that what's happening is that the
constant references are being resolved at compile-time, so that by the time
Y.a is run, the reference inside X.a has been permanently resolved to
X::A.

See what happens when you make this change:

  def X.a
    const_get("A")
  end

Now the constant is being resolved dynamically, and you'll get 1/2/3
in the output.

erm, yes.

true, but i think this makes it entirely weird.

so i call Y::a: self is Y, there is an A in Y but the A from X is used, right?

if i redefine X.a to

def X.a
   self::A
end

it's like i would expect it.

Ok, as this looks still completely odd to me (whatelse if not self would do as an implicit target?) there has to be a real good reason why it is this way, right? RIGHT?

(i don't have to call self.const_get(:A), why do i have to use self::A to get the A from self?)

David

/me still puzzled

cheers

Simon

Hi --

···

On Wed, 21 Sep 2005, ts wrote:

> aren't closures. I'm pretty sure that what's happening is that the
> constant references are being resolved at compile-time, so that by the time
> Y.a is run, the reference inside X.a has been permanently resolved to
> X::A.

Well not really : ruby *want* that you think that the constants are resolved
statically

[ruby-talk:32774]

"Those rules provide you the "illusion" of statically scoped constants."

Darn, I thought that by avoiding the word "statically" I was safe :slight_smile:

David

--
David A. Black
dblack@wobblini.net

/me still puzzled

Well another stupid example

   require 'a'
   
   class B < A
      X = 24
      def b
         X
      end
   end

   B::a

do you expect to have `24' when potentially you don't know that the method

Guy Decoux

···

A::a use the constant X ?