2

We can create a class and then create another class with the same name. That is not surprising.

[1] pry(main)> class A; end
=> nil
[2] pry(main)> a = A.new
=> #<A:0x0000000bd8a008>
[3] pry(main)> A = Class.new
(pry):3: warning: already initialized constant A
(pry):1: warning: previous definition of A was here
=> A
[4] pry(main)> new_a = A.new
=> #<A:0x0000000be001e0>
[5] pry(main)> a.class.name == new_a.class.name
=> true
[6] pry(main)> a.class == new_a.class
=> false
[7] pry(main)> a.class == A
=> false
[8] pry(main)> new_a.class == A
=> true

However, after redefining the constant we get what seems to be a collision: constant A and new_a.classmethod return the new class, while a.class returns the original class. These classes are different, yet they have the same name. How can this be possible and what exactly is going on when this code is executed?

Baldee
  • 117
  • 4
  • It’s the same situation like whether you have two “John Smith” entries in your phonebook. Eigenclasses differ. You might easily modify `a`’s eigenclass without overwriting constants (e.g. by opening and modifying it with [`class << self`](http://stackoverflow.com/questions/2505067/class-self-idiom-in-ruby)) and an effect would be the same. – Aleksei Matiushkin Feb 06 '15 at 12:30
  • I don't see what it has to do with eigenclasses. The `singleton_class` method is not even used in this code. Can you explain in more details? – Baldee Feb 06 '15 at 12:38
  • I put the example in the answer since it contains a lot of formatting. – Aleksei Matiushkin Feb 06 '15 at 12:44

4 Answers4

4

class A; end does two things:

  1. it creates a new class object
  2. it assigns this class object to the constant A

Removing or resassigning the constant only affects (2), it doesn't change the class object (1).

Ruby also sets the class name when assigning a class to a constant:

A.name #=> "A"

The class name is stored in a special instance variable (see below) and you see this name when inspecting an instance of your class:

A.new
#=> #<A:0x007febc1230848>
#     ^
#     |
#     +- this is A.name

The class name is independent of the constant a class is assigned to:

B = A

B.name #=> "A"
B.new  #=> #<A:0x007febc1313e68>

And this is why you can create multiple classes with the same name.

How the class name is stored internally

Ruby stores the class name in a special instance variable __classpath__. It can't be accessed from within Ruby, but if you would remove this restriction (I've patched Ruby for this example), you could read it:

A.instance_variable_get('__classpath__') #=> "A"

and even change it:

a = A.new #=> #<A:0x007fe0cd03ad30>
A.instance_variable_set('__classpath__', 'just a name')
A.name #=> "just a name"
a #=> #<just a name:0x007fe0cd03ad30>
Stefan
  • 109,145
  • 14
  • 143
  • 218
  • Thank you. So, there is no way to get a class just by its name (besides using `ObjectSpace.each_object`) in Ruby. We can do that only via variables/constants etc. Am I correct? – Baldee Feb 06 '15 at 15:43
  • Ruby assigns classes to constants because it's convenient. Regarding your initial question *"(...) they have the same name. How can this be possible (...) ?"* - I think once you understand that the class name is an attribute of the class object, it becomes obvious why two classes can have the same name. – Stefan Feb 06 '15 at 15:53
2

These classes are different, yet they have the same name. How can this be possible and what exactly is going on when this code is executed?

It's perfectly possible for two different objects to return the same value when you call a certain method. There's really nothing sophisticated about that:

a = [1, 2]
b = 'AB'

a.size # => 2
b.size # => 2

Note that both a and b return 2 when I call size, but that does not imply any sort of relationship at all between a and b.

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
0

It’s the same like having two “John Smith” entries in your phonebook. Consider we have a class:

class A
  def whoami
    puts 'original'
  end
end

Let’s now instantiate it:

a = new A
a_frozen = new A
a.whoami
#⇒ original
a_frozen.whoami
#⇒ original

Let’s modify a’s eighenclass:

class << a
  def whoami
    'modified'
  end
end

a.whoami
#⇒ modified
a_frozen.whoami
#⇒ original

And, of course, it’s still like:

a.class.name == a_frozen.class.name == 'A'

Name is the name only, nothing more. And there is no problem for different class instances share the same name.

Hope it helps.

Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
  • It does not at all. The code you've written does indeed add the 'whoami' method to the eigenclass, but I don't see how it is relevant to different classes having the same name, because `a` and `a_frozen` are instances of the same class and `a.class == a_frozen.class` returns `true`. Oh, and by the way, name is not "just a name", it is a constant in Ruby. So we basically get two constants with the same name and different values. Hence my confusion. – Baldee Feb 06 '15 at 13:12
  • No, we have _only one_ constant, of type `String`, containing string value `"A"`. My example shows how two instances of the same class might differ; I thought it would hint you how instances of two different classes might differ. It does not matter, that the names equal. Once an instance is created, it’s “operated” by it’s eigenclass and class name is just a nick for friends, nothing more. – Aleksei Matiushkin Feb 06 '15 at 13:33
0

a and new_a are instances of two different classes. You can access these classes with a.class and new_a.class. These classes are two instances of Class. They appear to have the same name they really are different classes, with different methods, etc.

class A
  def a
  end
end

a= A.new
A = Class.new
new_a = A.new

puts a.respond_to?(:a) # => true
puts new_a.respond_to?(:a) # => false
Thomas
  • 1,613
  • 8
  • 8
  • Yes, I agree. I wrote almost the same words, "These classes are different, yet they have the same name." But how exactly can this be possible and what exactly is going on when this code is executed? A class name is a constant. How is it possible for us to have two constants with different values? – Baldee Feb 06 '15 at 13:06
  • 1
    Huh? A class name is not a constant, it is a string. And you don't have one constant with two values, you have two different objects which return the same value when you call a certain method. That's not really surprising at all. `[1, 2].size` and `'AB'.size` both return `2` but that doesn't mean that they are somehow the same. – Jörg W Mittag Feb 06 '15 at 15:02