Calling instance method

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 :stuck_out_tongue:

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 :stuck_out_tongue:

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