Cross access between instance variables

I am working on a larger Ruby program, where instance variables of one
class need access to content of another class – I wonder how I should
solve this problem best.

Assume we have multiple fish tanks, each with multiple fishes. The
fishes should tell us if they like the temperature of the water. We can
solve this task when we gave each fish a reference to its tank:

[email protected] ~/pet $ cat fish_tank.rb
class Fish
def initialize(name, favorite_temperature, tank)
@tank = tank
@n = name
@t = favorite_temperature
end
def tell_state
if @tank.temperature < @t
puts ‘I feel cold’
elsif @tank.temperature = @t
puts ‘I feel well’
else
puts ‘I feel hot’
end
end
end

class Tank
attr_accessor :fish
attr_reader :temperature
def initialize(temperature)
@temperature = temperature
@fish = Array.new
end
end

t1 = Tank.new(18)
f1 = Fish.new(‘Ruby’, 21, t1)
t1.fish << f1
t1.fish.each{|f| f.tell_state}

I am more familiar with a situation, where the tank is a module, so the
fish can access module variables. But now we really need many tanks,
each with very many fishes. Currently it seems to be a bit strange
giving each of thousands fishes a reference to its tank. Another
solution may be to give the .tell_state() function a tank parameter each
time when we call it. (A tank-temperature parameter is not a good idea,
because we may need more, light, food…)

(For my real application the tanks are windows, and fishes are graphical
elements in each window, see
http://www.ssalewski.de/PetEd-Demo.html.en)

Do I miss something?

Best regards,

Stefan S.

On Thu, May 5, 2011 at 2:06 PM, Stefan S. [email protected]
wrote:

def initialize(name, favorite_temperature, tank)
puts ‘I feel hot’
end
giving each of thousands fishes a reference to its tank. Another
Best regards,

Stefan S.

Great question! It’s especially important when the fish / tank start
affecting each other, ie cold tank takes away 10 life units from the
fish,
should the tank do this to the fish, or should the fish look at the tank
and
do it to itself? If it should be the fish, then what if it only happens
during certain tank conditions such as proximity to other fish? So maybe
it
should be the tank doing this task, but what if the fish is feeling
friendly
that day, and can tolerate proximity to other fish? They are so
dependent on
each other, who is responsible for what, and how should that
relationship be
established?

I’m eager to see responses to this, I’ve run into the same issue in the
past, and was never satisfied with my solutions.

On Fri, 2011-05-06 at 17:25 +0900, Johannes Held wrote:

On 05.05.2011 21:06, Stefan S. wrote:

But now we really need many tanks, each with very many fishes.
Currently it seems to be a bit strange giving each of thousands
fishes a reference to its tank.
You can control the fishes within the tank. Every fish is saved in an
array in tank. The tank queries every fish for it’s mood

2011/5/7 Stefan S. [email protected]:

Of course this is a way to solve the problem. It may look not very
natural, that we have to tell the fish the parameters of its tank, when
we ask the fish about its mood:

mood = fish.tell_mood({:temp => t.temp, :food => t.food_type})

But OK, this is the way to do it. Now I know that I have not missed
something.

A little late to this, but isn’t this a good case for the Observer
pattern?
So the fish are always “aware” of the tank environment? Very simply:


require ‘observer’

class Tank
include Observable

def temperature
@temperature
end

def temperature=(temperature)
@temperature = temperature
changed
notify_observers(temperature)
end

end

class Fish

attr_accessor :tank_temperature

def initialize(tank)
@tank_temperature = tank.temperature
tank.add_observer(self)
end

def update(temperature)
puts “temperature changed to #{temperature}”
@tank_temperature = temperature
end

end

And exercise with:

require ‘tank’
require ‘fish’

tank = Tank.new
tank.temperature= 100
fish = Fish.new(tank)
puts “fish.tank_temperature: #{fish.tank_temperature}” # => 100

tank.temperature= 102
puts “fish.tank_temperature: #{fish.tank_temperature}” # => 102

On Sat, May 7, 2011 at 4:36 PM, John F. [email protected]
wrote:

You add fish to a tank, not tanks to a fish.

POV - you could as well say you “assign” a tank to a particular fish :slight_smile:

And actually, if I were implementing this myself, I’d probably separate
the Tank from the Environment it provides and have the Fish observe
its environment.

As always, YMMV.

You add fish to a tank, not tanks to a fish.

POV - you could as well say you “assign” a tank to a particular fish :slight_smile:

Perhaps, but in this model, at least, the fish can’t exist without the
tank, while the same is not true of a tank without the fish. So that’s
a strong motivation for considering putting fish in a tank, rather
than the other way around.

And actually, if I were implementing this myself, I’d probably separate
the Tank from the Environment it provides and have the Fish observe
its environment.

There’s lots of ways to skin this cat (as there are with pretty much
any software problem). I was just picking what I thought was the
STTCPW.

~ jf

John F.
Principal Consultant, BitsBuilder
LI: http://www.linkedin.com/in/johnxf
SO: http://stackoverflow.com/users/75170/

On Sat, May 7, 2011 at 20:31, Hassan S.

You add fish to a tank, not tanks to a fish. An alternative proposal,
that doesn’t involve Fish holding a reference to Tanks at all:

class Fish

def comfortable?(temp_in_degrees_celsius)
(@min@max).include? temp_in_degrees_celsius
end
end

class Tank

def add_inhabitant(i)
self.inhabitants << i
end

def update
# …
# possible temperature change!

self.inhabitants.each do |inhabitant|
  logger.warn("#{inhabitant} is experiencing environmental

stress") unless inhabitant.comfortable?(t)
end
end
end

John F.
Principal Consultant, BitsBuilder
LI: http://www.linkedin.com/in/johnxf
SO: http://stackoverflow.com/users/75170/

On Sat, May 7, 2011 at 19:27, Hassan S.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs