Project

General

Profile

Actions

Bug #19269

closed

Constant lookup and #instance_eval

Added by andrykonchin (Andrew Konchin) over 2 years ago. Updated over 2 years ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:111451]

Description

I've noticed a confusing behaviour of #instance_eval (and #instance_exec as well). In some cases it doesn't see constants defined in the object class.

Examples:

C = 1

class A
  C = 2
end

When #instance_eval is called with a String - A::C constant is visible, that is pretty expected:

A.new.instance_eval("C") # => 2

But when it's called with a block - A::C isn't visible:

A.new.instance_eval { C } # => 1

If we define a method that returns a constant (defined in the class), then A::C is visible in both cases:

C = 1

class A
  C = 2
  def c; C; end
end

A.new.instance_eval("c") # => 2
A.new.instance_eval { c } # => 2

So we see that when #instance_eval called with a block and a constant is accessed directly is the only case when a class constant isn't visible.

Wondering whether it's an expected behaviour and the reason to behave this way.


In the examples above I've added a top-level declaration C=1 only for readability. Without this declaration in all the cases when C value 1 is returned - a NoName exception is raised (uninitialized constant C (NameError))


Related issues 1 (0 open1 closed)

Has duplicate Ruby - Bug #19270: Constants lookup and a singleton class issueClosedActions

Updated by zverok (Victor Shepelev) over 2 years ago

As far as I understand, name lookup in block is performed related to the context where the block is defined.

The example with c (local name) works, because in instance_eval, it is implicitly self.c. But wouldn't work if you'll shadow the name with local variable:

C = 1

class A
  C = 2
  def c; C; end
end

c = 1

A.new.instance_eval("c") # => 2
A.new.instance_eval { c } # => 1

The block could've come from completely different context, and the block is "closure": it remembers the context from where it came from. It is not specific to instance_eval or constants, that's just how the blocks work.

(With instance_eval(string), there is no contexts it carries with itself, so it is interpreted in the target context.)

This would work unambiguously (but is tedious to write:

C = 1

class A
  C = 2
  def c; C; end
end

c = 1

A.new.instance_eval { self.c } # => 2
A.new.instance_eval { self.class::C } # => 2
Actions #2

Updated by nobu (Nobuyoshi Nakada) over 2 years ago

  • Has duplicate Bug #19270: Constants lookup and a singleton class issue added
Actions #3

Updated by andrykonchin (Andrew Konchin) over 2 years ago

  • Description updated (diff)
Actions #4

Updated by andrykonchin (Andrew Konchin) over 2 years ago

  • Description updated (diff)

Updated by Eregon (Benoit Daloze) over 2 years ago

  • Status changed from Open to Closed

This is expected because constant lookup is lexicial, i.e., it's only changed by module/class keywords, and by eval'ed strings.

Updated by andrykonchin (Andrew Konchin) over 2 years ago

@zverok (Victor Shepelev)

Thank you for clarification 🙇.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0