1

I'm pretty new to Ruby and seems that I'm still confused with mixin and including modules in classes. I would like to be able to access instance variables (@) defined in modules in classes. I have the following piece of code:

module ModuleB
  attr_reader :b

  def ModuleB.initialize(browser)
    puts "initialize from ModuleB"
    @browser = browser
    @b = 5
  end
end

module ModuleA
  attr_reader :a
  include ModuleB

  def ModuleA.initialize(browser)
    ModuleB.initialize(browser)
    puts "initialize from ModuleA"
    @browser = browser
    @a = @b
  end

  def action_1
    @a = @b + 1
    return @a
  end
end

class ClassA
  include ModuleA
  def initialize(browser)
    ModuleA.initialize(browser)
    @browser = browser
    puts 'initialize - method in ClassA'
    @c = @a
    @d = @b
    puts "a = #{@a}"
    puts "b = #{@b}"
    puts "c = #{@c}"
    puts "d = #{@d}"
  end

end

s = 'hello'
instA = ClassA.new(s)
puts instA.action_1

And here's the output that I get:

initialize from ModuleB
initialize from ModuleA
initialize - method in ClassA
a =
b =
c =
d =
mixin_example2.rb:23:in `action_1': undefined method `+' for nil:NilClass (NoMethodError)
        from mixin_example2.rb:46:in `<main>'

Seems like @a and @b are uninitialized. Additional thing, is that I cannot use '+' operator in action_1 method. What did I miss?

Sorry if I repeated problem that might have already been raised but I didn't find an answer so far.

3
  • This seems like it should be an inheritance pattern not a module pattern. Using inheritance makes this smoother more functional and more obvious Commented May 26, 2017 at 12:54
  • mixin inheritance is inheritance, though. In fact, include simply creates a class and makes that class the superclass. Commented May 26, 2017 at 13:10
  • @engineersmnky, in fact what I'm trying to do (not shown in this piece of code) is to get multiple inheritance using modules. Commented May 27, 2017 at 4:09

1 Answer 1

2

Instance variables belong to instances (which is why they are called "instance variables"). You have three objects of interest here, every single one of which has its own @b which has nothing to do with any of the other @bs of the other objects: ModuleA has its own @b, as does ModuleB, and instA also has its own @b.

Here is a more sensible implementation of what you are trying to do:

module ModuleB
  def initialize(browser)
    puts "initialize from ModuleB"
    @browser = browser
    @b = 5
  end
end

module ModuleA
  include ModuleB

  def initialize(browser)
    super
    puts "initialize from ModuleA"
    @a = @b
  end

  def action_1
    @a = @b + 1
  end
end

class ClassA
  include ModuleA

  def initialize(browser)
    super
    puts 'initialize - method in ClassA'
    @c = @a
    @d = @b
    puts "a = #@a"
    puts "b = #@b"
    puts "c = #@c"
    puts "d = #@d"
  end
end

s = 'hello'
instA = ClassA.new(s)
# initialize from ModuleB
# initialize from ModuleA
# initialize - method in ClassA
# a = 5
# b = 5
# c = 5
# d = 5
#=> #<ClassA:0x007f8b5f12e110 @a=5, @b=5, @browser="hello", @c=5, @d=5>

puts instA.action_1
# 6
Sign up to request clarification or add additional context in comments.

9 Comments

Excellent answer although in my opinion still less obvious than a direct class to class inheritance pattern. Although I understand your point regarding inclusion's superclass injection.
Thank you very much @Jorg. That's very clean code that I needed. However, I don't get your comment that there are 3 instances of @b in the code above: one for ModuleA, one for ModuleB and one for ClassA. If I instantiate object from ClassA how do I access @b from modules that are included? Isn't it just a single @b accessible on ClassA instance from superclass?
Also, one more comment but I'll probably create new question: if classA in fact inherited from 2 modules (let's say there was additional ModuleC) through includes, how could both superclass initialize methods be called?
@PiotrGesicki: Instance variables belong to objects. Each object has its own set of instance variables that are completely private to that particular object. The instance variable @foo of object a is completely separate from the instance variable @foo of object b. In your code, there are three different objects, all of which have an instance variable @b: ModuleA, ModuleB, and instA all have an instance variable named @b. But they are three different objects. They have nothing to do with each other. The fact that you set instance variable @b of ModuleA to some value …
… has absolutely no effect whatsoever on the instance variable @b of object ModuleB or the instance variable @b of object instA.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.