Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can one Ruby object destroy another?

In Ruby, can one object destroy another?

For example:

class Creature
  def initialize
    @energy = 1
  end
  attr_accessor :energy
 end

class Crocodile < Creature
  def eat(creature)
    @energy += creature.energy
    creature = nil #this does not work
  end
end

fish = Creature.new
croc = Crocodile.new
croc.eat(fish)

After the crocodile has eaten a creature and absorbed its energy, the creature should cease to exist. But the code above doesn't destroy the creature.

I know that if I say fish = nil, the object that the varible fish refers to will be garbage collected. But saying creature = nil inside the Crocodile's eat method doesn't accomplish that.

Another way of putting it

From inside croc.eat, can I say "since the variable 'fish' was passed to me, when I'm done, I'm going to set 'fish' to nil?"

Update: problem solved

I've essentially taken the approach that Chuck suggested, with some modifications. Here was my reasoning:

  1. If there is no longer any variable pointing to an object, it will be garbage collected
  2. If, when an object is created, I add it to a hash (like 'x' => object), and don't create any other variable for it, then deleting that item from the hash results in garbage collecting the object
  3. It seems logical that a list of all creatures should be stored in the Creature class

Therefore, I did this:

  1. On the Creature class object, I created a hash and assigned it to an instance variable. We'll call it @creaturelist. (The reason I used an instance variable and not a class variable is so that any subclass of Creature can have its own list, too.)
  2. In the Initialize method, a new creature hands itself to the Creature class
  3. The Creature class adds a reference to that creature to @creaturelist and returns an ID to the creature.
  4. The creature remembers that ID in its own @id variable.
  5. If the creature dies, it calls the parent class with Creature.remove(@id), and the only reference to itself gets deleted.

Now I can do this:

class Predator < Creature
  def eat(creature)
    @energy += creature.energy
    creature.die
  end
end

fish = Creature.new
Creature.list #shows the fish
croc = Predator.new
croc.eat(fish)
Creature.list #no more fish

Of course, in this example, fish still points to that creature object, so it's not garbage collected. But eventually, creatures will be created and eat each other based on rules, so I won't be individually naming them.

like image 353
Nathan Long Avatar asked Dec 23 '09 22:12

Nathan Long


1 Answers

I think the problem is that you're thinking of the program itself as the world in which these simulated things live rather than simulating one.

fish = Creature.new
croc = Crocodile.new
$world = [fish, croc]
class Crocodile
  def eat(creature)
    @energy += creature.energy
    $world.delete creature
  end
end
croc.eat fish
world # [croc], now all by his lonesome, the last creature in the world :(

And assuming the fish variable had gone out of scope like it would in a properly structured program, that object would most likely now be garbage.

like image 86
Chuck Avatar answered Nov 15 '22 06:11

Chuck