Class variables and self

I'm currently reading The Well-Grounded Rubyist. In the section about
class variables, instance variables, and self they have this class as an
example:

class Car
  @@makes = []
  @@cars = {}

  attr_reader :make

  def self.total_count
    @total_count || 0
  end

  def self.total_count=(n)
    @total_count = n
  end

  def self.add_make(make)
    unless @makes.include?(make)
      @@makes << make
      @@cars[make] = 0
    end
  end

  def initialize(make)
    if @@makes.include?(make)
      puts "Creating a new #{make}!"
      @make = make
      self.class.total_count += 1
    else
      raise "No such make: #{make}."
    end
  end

  def make_mates
    @@cars[self.make]
  end
end

My question is in the initialize method about the line:

  self.class.total_count += 1

what is the purpose of the 'class' in that statement?

thanks,
mike

···

--
Posted via http://www.ruby-forum.com/.

Mike Glaz wrote in post #1063872:

My question is in the initialize method about the line:

  self.class.total_count += 1

what is the purpose of the 'class' in that statement?

self.class is (obviously) the class of self, so in this case it's Car.
You may actually write Car.total_count, but then you'll get trouble with
renaming and inheritance.

···

--
Posted via http://www.ruby-forum.com/\.

Since total_count is a method of class Car, inside the initialize method of an instance you can refer to class Car as self.class. It would seem simpler to say Car::total_count in this particular case.

···

On Jun 9, 2012, at 2:43 PM, Mike Glaz <lists@ruby-forum.com> wrote:

I'm currently reading The Well-Grounded Rubyist. In the section about
class variables, instance variables, and self they have this class as an
example:

class Car
@@makes =
@@cars = {}

attr_reader :make

def self.total_count
   @total_count || 0
end

def self.total_count=(n)
   @total_count = n
end

def self.add_make(make)
   unless @makes.include?(make)
     @@makes << make
     @@cars[make] = 0
   end
end

def initialize(make)
   if @@makes.include?(make)
     puts "Creating a new #{make}!"
     @make = make
     self.class.total_count += 1
   else
     raise "No such make: #{make}."
   end
end

def make_mates
   @@cars[self.make]
end
end

My question is in the initialize method about the line:

self.class.total_count += 1

what is the purpose of the 'class' in that statement?

so is self.total_count equal to self.class.total_count?

mike

···

--
Posted via http://www.ruby-forum.com/.

Mike Glaz wrote in post #1063878:

so is self.total_count equal to self.class.total_count?

No, of course not. self refers to the particular instance of Car,
whereas self.class refers to the *class* of this instance, i. e. Car
itself. Those are two completely different objects.

Since the instances of Car don't even have a total_count method, calling
self.total_count will throw an exception (try it yourself).

It's important to distinguish between the methods of the class and the
methods of the instances. The Car class has three new methods:
total_count, total_count= and add_make. The instances of Car also have
three new methods: make_mates, initialize and make (the latter is
created by attr_reader).

Check it for yourself:

puts Car.methods(false)
my_ferrari = Car.new('Ferrari')
puts my_ferrari.methods(false)

The "false" argument suppresses the inherited methods.

···

--
Posted via http://www.ruby-forum.com/\.

Nope. Assuming that "self" at that time is an individual Car,
self.total_count would be an instance variable on that Car.
self.class.total_count belongs to class Car, because that's
self.class.

Think of it like a literal class, like in a classroom in school. Self
(in this situation) is an individual student. He doesn't have a
total_count. But the class itself does.

-Dave

···

On Sat, Jun 9, 2012 at 5:20 PM, Mike Glaz <lists@ruby-forum.com> wrote:

so is self.total_count equal to self.class.total_count?

--
Dave Aronson, Cleared/Remote Ruby on Rails Freelancer
(NoVa/DC/Remote); see www.DaveAronson.com, and blogs at
www.Codosaur.us, www.Dare2XL.com, www.RecruitingRants.com

It depends where they are called. You need to know what self is at the point where the call is made. Going back to your sample code...

class Car

# At the point self == Car so self.total_count is the same as Car.total_count.
# Note that this a method declaration, you are defining a class method.
def self.total_count
   @total_count || 0
end

[snip]

def initialize(make)
  [snip]

# At this point, inside a method declaration self == an instance of Car NOT Car.
# So self.class is Car therefore this statement is the same as Car.total_count.
     self.class.total_count += 1
  
So in answer to your question, Yes they are the same object. Understanding when self changes and to what is a pretty important concept in Ruby.

Henry

···

On 10/06/2012, at 9:20 AM, Mike Glaz wrote:

so is self.total_count equal to self.class.total_count?

Henry Maddocks wrote in post #1063893:

···

On 10/06/2012, at 9:20 AM, Mike Glaz wrote:

so is self.total_count equal to self.class.total_count?

It depends where they are called. You need to know what self is at the
point where the call is made. Going back to your sample code...
[...]
So in answer to your question, Yes they are the same object.

No, they are never the same object. self.class in the context of Car is
not Car but Class, because the class of a class is Class.

The only context where self and self.class are the same is the context
of Class, because Class is an instance of itself.

--
Posted via http://www.ruby-forum.com/\.

Did you read what I wrote? I said, it depends where the calls are made.

I assumed the OP was asking the question based on the code that he posted. The two calls were made in different parts of the code where self were different objects.

1.9.3p125 :021 > class Car
1.9.3p125 :022?> # Here self == Car
1.9.3p125 :023 > p self
1.9.3p125 :024?>
1.9.3p125 :025 > def initialize
1.9.3p125 :026?> # Here self is an instance of Car so self.class == Car
1.9.3p125 :027 > p self.class
1.9.3p125 :028?> end
1.9.3p125 :029?>
1.9.3p125 :030 > end
Car
=> nil
1.9.3p125 :031 >
1.9.3p125 :032 > Car.new
Car
=> #<Car:0x007fcc1a3fca30>
1.9.3p125 :033 >

self and self.class are both Car. Sure if they two calls were made in the same context they would return different objects but, this isn't the case in the code the OP posted.

Henry

···

On 10/06/2012, at 12:02 PM, Jan E. wrote:

No, they are never the same object. self.class in the context of Car is
not Car but Class, because the class of a class is Class.

The only context where self and self.class are the same is the context
of Class, because Class is an instance of itself.