Confusion with #class_eval with block form and with no block form

class Foo
@@x = 10
end

Foo.class_eval(’@@x’) # => 10 # Part-I
Foo.class_eval{ @@x } # => # Part - II

~> -:5:in `block in ': uninitialized class variable @@x in

Object (NameError)

~> from -:5:in `class_eval’

~> from -:5:in `’

Why does Part-I and Part-II behave differently ?

Here’s a snippet I wrote while playing around:

class Foo; class_eval{ @@x }; end
=> 10

This leads me to believe it might be a scoping or lookup issue? There
seems
to be a rule at play here that I can’t put my finger on. I’m a bit
confused
only because the following works:

class Foo; @x = 42; end
=> 42

Foo.class_eval{ @x }
=> 42

Hi Arup R.,

The Ruby documentation gives a clue …
class_eval(string [, filename [, lineno]]) → obj
Evaluates the string or block in the context of mod, except that when
a block is given, constant/class variable lookup is not affected.
Source:
http://www.ruby-doc.org/core-2.1.0/Module.html#method-i-class_eval

So, when you do
Foo.class_eval { @@x }
… with a block given, the scope of @@x doen’t change and @@x is
“scoped” on Object.

I try to think this as simply as an iterator having access to the
surrounding local vars.

collection = [ “bananas”, “oranges”, “apples”]
local_var = "I like "
collection.each { |fruit| puts local_var + fruit }

So, class_eval just “try” to get the “@@x” from the outermost context
(not inside the Foo class).

class Foo
@@x = 10
end

The context where this @@x bellow is it is Object

Foo.class_eval { @@x }

=> NameError: uninitialized class variable @@x in Object

class Bar
Foo.class_eval { @@x }
end

=> NameError: uninitialized class variable @@x in Bar

Inside the “class Bar” definition, @@x is scoped on Bar, not Object.

More…

At Dave T. book we can read…

“Class variables belong to the innermost enclosing class or module.
Class variables used at the top level are defined in Object, and
behave like global variables. Class variables defined within singleton
methods belong to the receiver if the receiver is a class or a module;
otherwise, they belong to the class of the receiver.”
Source:
http://www.ruby-doc.org/docs/ruby-doc-bundle/ProgrammingRuby/book/language.html

In a newer version it says “Class variables defined within singleton
methods belong to the top level (although this usage is deprecated and
generates a warning).”

Try this also:

class Foo
@@x
end

I think this is like class_eval with a String

Foo.class_eval("@@x")

class << Foo # The eingenclass of the Foo class
@@x
end

(ruby 1.8.7) warning: class variable access from toplevel singleton

method

(ruby 2.1.0) warning: class variable access from toplevel

NameError: uninitialized class variable @@x in Object

I think this is like class_eval with a block

Foo.class_eval { @@x }

More important than the above is to remember that we should favor
class instance variables rather than class variables when possible.
http://jvans1.github.io/blog/2013/01/06/class-variables-vs-class-instance-variables/
It’s just less complicated! :wink:

Abinoam Jr.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs