I feel like I’ve really missed something obvious here, but do you guys
know how to call a specific method for every instance of a given class?
Or rather can you help me with a problem I’ve been having lately?
I’ve been storing all my instances from different classes in an array I
call @insts , but I want to call the method ‘destroy’ in every instance
so I do this:
@insts.each { |inst|
if inst.respond_to?(‘destroy’)
inst.destroy
end
}
I check to make sure it responds to the method so I dont cause an error,
but when I run the code its only a handful of the instances that runs
the method… Why?
Here’s a sample project that illustrates my problem:
https://www.dropbox.com/s/h76019vcj5do3ln/instance.zip
When you press Space its supposed to destroy every box in the game.
10 out of 10 here:
class Dog
def destroy
puts “I’m destroyed”
end
end
insts = []
10.times do
insts << Dog.new
end
insts.each do |inst|
if inst.respond_to? ‘destroy’
inst.destroy
end
end
–output:–
I’m destroyed
I’m destroyed
I’m destroyed
I’m destroyed
I’m destroyed
I’m destroyed
I’m destroyed
I’m destroyed
I’m destroyed
I’m destroyed
Okay thanks for your reply. I now know that the problem isn’t the way I
call the method, because my problem only occurs when I call
“@window.destroy_instance(self)” for some reason
And I further realized that whenever I call destroy on every instance,
the amount destroyed = (amount of instances / 2).ceil , which is pretty
interesting to me…
It probably has something to do with the array itself rather than the
method not being called. I’ll have to further inpect this issue now 
Lucas Jørgensen wrote in post #1151812:
Okay thanks for your reply. I now know that the problem isn’t the way I
call the method, because my problem only occurs when I call
“@window.destroy_instance(self)” for some reason
And I further realized that whenever I call destroy on every instance,
the amount destroyed = (amount of instances / 2).ceil , which is pretty
interesting to me…
It probably has something to do with the array itself rather than the
method not being called. I’ll have to further inpect this issue now 
Always make sure that your array actually has the right object stored.
when I run the code its only a handful of the instances that
runs the method… Why
The logical conclusion:
You must have stored objects in your array that do not respond
to the :destroy method.
Try to look where you add new stuff to your array, you probably
added wrong objects.
Thanks again, but the array does have all the instances stored, as I
found that the problem only occured when I had
“@window.instance_destroy(self)” in the ‘destroy’ method, like so:
def destroy
@window.instance_destroy(self)
end
But if I instead wrote something like this:
def destroy
puts “I’m destroyed”
end
It works just fine and every instance runs the method.
But it gets even weirder when I write this:
def destroy
puts “I’m destroyed”
@window.instance_destroy(self)
end
In this case it’s still only half the instances that gets destroyed and
puts “I’m destroyed” , where the rest don’t even run the method…
So to me it seems to be a problem with the
@window.instance_destroy(self) command, but I just can’t see why!?
Alright I’ve realized that you guys probably dont know the details of
what I’m talking about when you dont have the code, so I already
uploaded a sample project in my first post. In case you dont want to
download the code I’ll write a relevant snippet here:
class Main < Gosu::Window
def initialize
super(640, 400, false)
@insts = []
20.times do
@insts << Box.new(rand(600)+20, rand(360)+20, self)
end
end
def instance_destroy(inst)
@insts.delete(inst)
end
def button_down(id)
if id == Gosu::KbSpace
@insts.each do |inst|
if inst.respond_to?(‘destroy’)
inst.destroy
end
end
end
end
def draw
@insts.each { |inst| inst.draw }
end
end
class Box
def initialize(x, y, window)
@x, @y, @window = x, y, window
end
def destroy
puts “I’m destroyed”
@window.instance_destroy(self)
end
def draw
# Draw the box here
end
end
The actual code is a bit longer than this, but the rest isn’t really
relevant… I’ve also made a few adjustments compared to the files I’ve
uploaded in my first post, but this should explain it.
Lucas Jørgensen wrote in post #1151875:
But if I instead wrote something like this:
def destroy
puts “I’m destroyed”
end
It works just fine and every instance runs the method.
But it gets even weirder when I write this:
def destroy
puts “I’m destroyed”
@window.instance_destroy(self)
end
In this case it’s still only half the instances that gets destroyed and
puts “I’m destroyed” , where the rest don’t even run the method…
Typically, when you destroy a window (e.g. instance_destroy???) all the
widgets that are children of the window also get destroyed. So it is
possible that when you destroy @window, you are destroying some
of the objects in your array.
What widget framework are you using? Also, could you please post
your code? You shouldn’t ask people to download code from an
untrusted source.
Run the following and examine the output:
data = [10, 20, 30, 40, 50]
data.each do |num|
puts num
data.delete(num)
end
Next run the following and examine the output:
data = [10, 20, 30, 40, 50]
data.each_with_index do |num, i|
p data
puts i
puts num
data.delete(num)
puts ‘-’ * 10
end
Note that i is the index position in the array that each() is currently
fetching. The bottom line: never, ever, ever, never delete things from
an array(or any other collection) while you are iterating over the
array.
7stud – wrote in post #1151892:
Run the following and examine the output:
data = [10, 20, 30, 40, 50]
data.each do |num|
puts num
data.delete(num)
end
Next run the following and examine the output:
data = [10, 20, 30, 40, 50]
data.each_with_index do |num, i|
p data
puts i
puts num
data.delete(num)
puts ‘-’ * 10
end
Note that i is the index position in the array that each() is currently
fetching. The bottom line: never, ever, ever, never delete things from
an array(or any other collection) while you are iterating over the
array.
Thank you so much!! Now I understand what’s happening with the array,
but the solution still isn’t as obvious to me… I was hoping there would
be some easy way around this, but it seems I’ll have to do more research
on arrays to do so. In any case this definitely helped me!
the solution still isn’t as obvious to me.
-
@insts.dup.each do |inst|
inst.destroy if inst.respond_to?(‘destroy’)
end
-
class Dog
def destroy
puts “I’m destroyed”
end
end
insts = []
insts << 10
10.times do
insts << Dog.new
end
insts.delete_if do |inst|
if inst.respond_to? ‘destroy’
inst.destroy
true
else
false
end
end
p insts
–output:–
I’m destroyed
I’m destroyed
I’m destroyed
I’m destroyed
I’m destroyed
I’m destroyed
I’m destroyed
I’m destroyed
I’m destroyed
I’m destroyed
[10]
Thank you, although I found another way to destroy the instances, which
was:
def destroy_all_instances
@insts.each_with_index do |num, i|
if @insts[i].respond_to?(‘destroy’)
@insts[i].destroy
@insts[i] = nil
end
end
@insts.delete(nil)
end
That way it doesn’t mess up the array, while destroying the instances.
Lucas Jørgensen wrote in post #1151978:
def destroy_all_instances
@insts.each_with_index do |num, i|
if @insts[i].respond_to?(‘destroy’)
@insts[i].destroy
@insts[i] = nil
end
end
@insts.delete(nil)
end
perhaps this one is simpler and more robust:
def destroy_all_instances
@insts.shift.tap { |box|
box.destroy if box.respond_to(‘destroy’)
} while @insts.size>0
end