Initializing Instance Variables in Mixins

Initializing instance variables in Mixins

module Example
def self.included(base)
base.instance_variable_set :@example_ivar, :foo
end
end

Edit: Note that this is setting a class instance variable. Instance variables on the instance can't be created when the module is mixed into the class, since those instances haven't been created yet. You can, though, create an initialize method in the mixin, e.g.:

module Example
def self.included(base)
base.class_exec do
def initialize
@example_ivar = :foo
end
end
end
end

There may be a way to do this while calling the including class's initialize method (anybody?). Not sure. But here's an alternative:

class Foo
include Example

def initialize
@foo = :bar
after_initialize
end
end

module Example
def after_initialize
@example_ivar = :foo
end
end

Initialize instance variable in a mixin

I would propose to put that in an __init__() of the Mixin. What do you think is the disadvantage?

class Mixin(object):
def __init__(self, *args, **kwargs):
super(Mixin, self).__init__(*args, **kwargs)
self.items = []

I think this is right way to do it; all other (maybe working) solutions look like a hack to me.

Ruby mixin - accessing module instance variables in class instances

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

Javascript mixin pattern setting instance specific this variables

You could inherit all mixable objects from a base object that ensures proper initialization. This is a clean way of achieving your goal.

The following code demonstrates this principle:

//------------ framework

var inherits = function(childCtor, parentCtor) {
function tempCtor() {};
tempCtor.prototype = parentCtor.prototype;
childCtor.superClass_ = parentCtor.prototype;
childCtor.prototype = new tempCtor();
childCtor.prototype.constructor = childCtor;
};

var mixIn=function(target,source){
for(fn in source){
if(source.hasOwnProperty(fn) && fn.name != 'init'){
target.prototype[fn]=source[fn];
}
}

if (typeof source.init == 'function') {
if (target.prototype._mixInits === undefined) {
target.prototype._mixInits = [];
}
target.prototype._mixInits.push(source.init);
}
};

// all objects that can be mixin's should inherit from
// this object in order to ensure proper initialization
var Mixable = function() {
var mixInits = this.__proto__._mixInits;
if (mixInits !== undefined) {
for (var i = 0; i < mixInits.length; i++) {
mixInits[i].call(this);
}
}
};

//------------ testcode

var SpeakEnable = {
say:function(){
console.log(this.message);
},
init:function(){
console.log('say init called');
this.message="Saying Hello World Mixed in!";
this.object=[];
}
};

var WalkEnable = {
walk:function(){
console.log(this.walk_message);
},
init:function(){
console.log('walk init called');
this.walk_message="Walking step 1.2.3.";
}
};

var Person=function() {
Mixable.call(this);
};

inherits(Person, Mixable);

mixIn(Person,SpeakEnable);
mixIn(Person,WalkEnable);

var lulu=new Person();
lulu.say();
lulu.walk();

How do you access an instance variable within a mixin method?

In general, avoid having mixins access member variables: It's a very tight form of coupling that can make future refactoring unnecessarily difficult.

One useful strategy is for the Mixin to always access variables via accessors. So, instead of:

#!/usr/bin/ruby1.8

module Mixin

def do_something
p @text
end

end

class Foo

include Mixin

def initialize
@text = 'foo'
end

end

Foo.new.do_something # => "foo"

the mixin accesses the "text" accessor, which is defined by the including class:

module Mixin

def do_something
p text
end

end

class Foo

attr_accessor :text

include Mixin

def initialize
@text = 'foo'
end

end

Foo.new.do_something # => "foo"

What if you need to include the Mixin in this class?

class Foo

def initialize
@text = "Text that has nothing to do with the mixin"
end

end

Using generic and common data names in mixins can lead to conflicts when the including class uses the same name. In that case, have the mixin look for data with a less common name:

module Mixin

def do_something
p mixin_text
end

end

and let the including class define the appropriate accessor:

class Foo

include Mixin

def initialize
@text = 'text that has nothing to do with the mixin'
@something = 'text for the mixin'
end

def mixin_text
@something
end

end

Foo.new.do_something # => "text for the mixin"

In this way, the accessor acts as sort of "impedance matcher" or "translator" between the mix-in's data and the including class's data.

Does Instance Variables of a module shared between class with the mixin?

In Ruby modules and classes are objects, so it's possible to set instance variables for them.

module Test
@test = 'red'
def self.print_test
puts @test
end
end

Test.print_test #=> red

Your mistake is thinking that the variable @color is the same for:

module SharedVar
@color
end

and

module SharedVar
def show_color
@color
end
end

which is not.

In the first example, the instance variable belongs to the SharedVar object and in the second example the instance variable belongs to the object you include the module in.

Another explanation by self pointer. In the first example the self pointer is set to the module object SharedVar, so typing @color will refer to the object SharedVar and there's no connection with another object. In the second example, the method show_color can be called only on some object, i.e. ex1.show_color, so the self pointer will point to ex1 object. So in this case the instance variable will refer to ex1 object.



Related Topics



Leave a reply



Submit