I have two classes, each of which use methods from the other class. But
because they initialize an instance of each other, this creates an
infinite loop!
I would like to keep them separate and not merge them. What’s the best
/ most elegant / proper way of solving this problem? There is probably
something simple that I’m just not seeing.
Thanks for replying! Well, I’ve tested it and it works (see extended
example below). But I don’t know why it works!
Why set the arguments to nil? Why does @b = b || B.new(self) work?
The b = nil means that b is optional. If it is not passed by the
caller (as in: A.new), then the initial value of b is nil. If an
argument is provided by the caller (as in: A.new(self)), then that
value is assigned to b.
In those two cases, this line
@b = b || B.new(self)
will behave differently.
If b was passed in as an argument to A.new, then the effect is
@b = b
If not, then the effect is
@b = B.new(self)
Having these two cases is what makes it possible to set up the circular
reference that you wanted. When you construct an A like so:
a = A.new
there is no argument. So A.new calls B.new. The trick is that it calls
B.new with an argument: B.new(self). Since an argument is passed to
B.new, it simply assigns that argument (an instance of A) to its @a
attribute.
On 2013-09-02, at 12:31 AM, Joel VanderWerf [email protected]
wrote:
In those two cases, this line
@b = B.new(self)
Having these two cases is what makes it possible to set up the circular
reference that you wanted. When you construct an A like so:
a = A.new
there is no argument. So A.new calls B.new. The trick is that it calls B.new
with an argument: B.new(self). Since an argument is passed to B.new, it simply
assigns that argument (an instance of A) to its @a attribute.
Hope that helps…
Why not let Ruby do the defaulting for you? For example:
#!/usr/bin/env ruby
class A
def initialize(b = B.new(self)) @b = b
end
def method_foo
do something with b
end
end
class B
def initialize(a = A.new(self)) @a = a
end
I have two classes, each of which use methods from the other class. But
because they initialize an instance of each other, this creates an
infinite loop!
I would like to keep them separate and not merge them. What’s the best
/ most elegant / proper way of solving this problem? There is probably
something simple that I’m just not seeing.
I obviously don’t know the specifics of what you’re doing, but I have to
say the general pattern has a distinct odour to it. This smacks of
too-tightly coupled classes, and probably low cohesion. I’d seriously
consider refactoring this, and thinking it out a bit further so your
classes are more independent.
I obviously don’t know the specifics of what you’re doing, but I have to say the
general pattern has a distinct odour to it. This smacks of too-tightly coupled
classes, and probably low cohesion. I’d seriously consider refactoring this, and
thinking it out a bit further so your classes are more independent.
… or at least do not employ such a circular dependency for
construction.
I obviously don’t know the specifics of what you’re doing, but I have to say the
general pattern has a distinct odour to it. This smacks of too-tightly coupled
classes, and probably low cohesion. I’d seriously consider refactoring this, and
thinking it out a bit further so your classes are more independent.
A little “dependency injection” to decouple your classes…
class A
attr_reader :container
def initialize container @container = container
end
def b
container.b
end
def do_something_with_b
b.say_bar
end
def say_foo
puts “foo”
end
end
class B
attr_reader :container
def initialize container @container = container
end
def a
container.a
end
def do_something_with_a
a.say_foo
end
def say_bar
puts “bar”
end
end
class MyContainer
def a @a ||= A.new(self)
end
def b @b ||= B.new(self)
end
end
mc = MyContainer.new
mc.a.do_something_with_b # ==> bar
mc.b.do_something_with_a # ==> foo
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.