Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is an object different inside and outside of an iteration?

Tags:

ruby

constants

I assigned a class to a constant Foo, and reassigned Foo to something else:

class Foo; end
Foo = nil

In the main environment, Foo refers to the newly assigned object:

p Foo # => nil

But, within an iteration of some kind, (I am not sure which), Foo refers to the previous object:

ObjectSpace.each_object(Class).select{|c| c.name == "Foo"}
.each{|c| p c, c.instance_of?(Class)}
# => Foo
     true

Why is this?

like image 920
sawa Avatar asked Mar 24 '23 23:03

sawa


2 Answers

Assigning nil to the constant Foo doesn't affect the created class. It still exists, although you cannot refer to it with Foo anymore (unless you reassign the class object to Foo again).

class Foo; end
Foo.object_id
# => 70210590718440
Foo = nil
Foo.object_id
# => 4
Foo = ObjectSpace._id2ref(70210590718440)
Foo.object_id
# => 70210590718440

Regarding the name, creating a class with:

class Foo; end
Foo.name
# => "Foo"

assigns it to the contant Foo, just like:

Foo = Class.new
Foo.name
# => "Foo"

It also sets its name, but this doesn't make it a class. You can as well create classes without a name:

foo = Class.new
foo.name
# => nil

Assigning an unnamed class to a constant sets its name:

Bar = foo
foo.name
# => "Bar"

Once set, it doesn't change:

Baz = foo
foo.name
# => "Bar"
like image 153
Stefan Avatar answered Mar 26 '23 15:03

Stefan


The class you created exists and is reachable from the main ObjectSpace as long as it is not garbage collected.

The constant name Foo is merely a reference to the class object. Its internal name remains "Foo", even if accessed via other variable or constant names.

Try this, to demonstrate that even 'renamed' a, the name of the class is still "Foo":

class Foo; end
a = Foo
Foo = nil
puts a.name # prints Foo
like image 36
SirDarius Avatar answered Mar 26 '23 13:03

SirDarius