I am trying to keep count of instances of objects of a given class, inside the class that defines those objects.
First of all I am aware of code reflection and ObjectSpace.each_object, but I'd prefer not to use reflection and let the class itself be able to "look after" itself.
I looked around and all solutions I found seem to make use of @@class_variables in the class definition like, for example, the accepted answer to this question: How to get class instances in Ruby?
As I kept reading around though, I found that class variables in ruby can behave very bad in some situations... biggest reason being this:
A class variable defined at the top‐level of a program is inherited by all classes. It behaves like a global variable.
source & more info here: http://ruby.runpaint.org/variables#class
So, I tried to code a class that stores the number of its instantiated objects inside itself using a class instance variable instead of a class variable, and apparently it seems to work ok but since I am still learning about this "in-deep" language topics I'd like to ask you if the code I wrote is correct and/or makes sense:
class Pizza
@orders = 0
def self.new
@orders += 1
end
def self.total_orders
@orders
end
end
new_pizza = Pizza.new #=> 1
special_pizza = Pizza.new #=> 2
fav_pizza = Pizza.new #=> 3
One of my doubts is that overriding Pizza.new method i "delete" some important funcionality of the original .new method ? (What does the original .new method provide?? How can i "inspect" into a method code using reflection?) What else am I doing wrong, or totally wrong in my approach and why ?
Thanks
edit: forgot to add this important bit:
As a way to better constrain the scope of things, I'd like the Pizza class to be able to count only at object instantiation time and not to have a setter method on its @instance class variable, which can be accessed at anytime in code (Pizza.count = 1000). That's why I was trying to override "new".
I think this is the trickiest part which makes me ask myself is my approach is in the right direction, or if I simply should stop reling so much on these language mechanisms and instead add myself some logic to let the counting happen only if a object of a Pizza class has entered ObjectSpace..
I am just looking for the more elegant, non bloated way to obtain this using language features..
In either case help would be appreciated..
Thanks again.
You do not need to override new. Try this:
class Pizza
@count = 0
class << self
attr_accessor :count
end
def initialize
self.class.count += 1
end
end
Pizza.new
Pizza.new
puts Pizza.count
Please note that Pizza.count
will not go down when the pizzas are garbage collected, and it will not go up when they are dup
ed.
To answer your other questions: I'm not sure how you can inspect the new
method, but it is probably written in C so you should look in the Ruby source code. I think it basically does this.
def new(*args, &block)
o = allocate
o.initialize(*args, &block)
o
end
You could probably get away with overriding new as long as you called super
at some point. (Not saying this is a good idea, but for example:
class Foo
def self.new
# do whatever stuff you want here
super
end
end
)
you are right. using class variables is mind boggling some times. i always forget if the get inherited or not etc.
your approach is right, but...
NEVER override new
implement initialize
instead! it will get called during the init process of every object. see the docs here: http://apidock.com/ruby/v1_9_3_125/Class/new
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With