On Thu, Jan 23, 2003 at 12:20:45AM +0900, ahoward wrote:
> On Wed, 22 Jan 2003, Mauricio Fern?ndez wrote:
> 
> <snip>
> > >   module M
> > >     attr_accessor :x
> > >     @x = 42
> > Doesn't refer to the same thing!
> >  The former will be an iv. of objects extended with M _or_
> > instanciated from classes that include M.
> >  The later is a module instance variable, ie, an instance variable
> > associated to the 'M' object (that of class Module).
> > >   end
> > >
> > >   class Foo; include M; end
> > >
> > >   p Foo.new.x  # >> nil
> >
> > Because it's not the same @x!
> <snip>
> 
> that was my point.

This is why we like class instance variables :)
The interesting thing about them is that they belong _only_ to that
class, not to subclasses like class variables:

>> class A
>> @@var = 'A::@@var so to speak'
>> end
=> "A::@@var so to speak"
>> class B < A
>> def a
>> @@var
>> end
>> end
=> nil
>> B.new.a
=> "A::@@var so to speak"
>> class << A; def x= a; @x = a; end; end
=> nil
>> class << A; def x; @x; end; end
=> nil
>> class A
>> def interesting
>> self.class.x
>> end
>> end
=> nil
>> a = A.new
=> #<A:0x40266ec4>
>> A.x= 'belongs only to A'
=> "belongs only to A"
>> a.interesting
=> "belongs only to A"
>> B.new.interesting
=> nil 
 
For one stupid use of this, see below.

> <snip>
> > irb(main):001:0> module M
> > irb(main):002:1>  class << self; attr_accessor :x; end
> > irb(main):003:1> end
> > nil
> > irb(main):004:0> M.x = 1
> > 1
> > irb(main):005:0> M.x
> > 1
> <snip>
> 
> didn't know you could do that...

And that way you can for instance do the following (but take it with a
grain of salt, as I suspect somebody will find some horrible flaw :-P)

batsman@tux-chan:/tmp$ cat b.rb
module CountInstances
        def new(*args, &p)
                @instances ||= 0
                @instances += 1
                super *args, &p
        end

        def instances
                @instances || 0
        end
end

class A
        extend CountInstances
        def initialize
                puts "Creating instance of #{self.class}"
        end
end

class B < A
        # can have that functionality by subclassing A or using
        #extend CountInstances
end

puts "Made #{A.instances} instances of A."
puts "Made #{B.instances} instances of B."
2.times { A.new; B.new }
1.times { B.new }
puts "Made #{A.instances} instances of A."
puts "Made #{B.instances} instances of B."
batsman@tux-chan:/tmp$ ruby b.rb
Made 0 instances of A.
Made 0 instances of B.
Creating instance of A
Creating instance of B
Creating instance of A
Creating instance of B
Creating instance of B
Made 2 instances of A.
Made 3 instances of B.

It works because B < A but B.class is _not_ derived from A.class :) so
the @iv are not the same one depending on initialization order as for
normal instance vars.


> <snip>
> > The only ways to access module instance variables are through the
> > accessors and instance_eval, AFAIK.
> <snip>
> 
> AFAIK -> ???

AFAIK, IIRC :)

-- 
 _           _                             
| |__   __ _| |_ ___ _ __ ___   __ _ _ __  
| '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \ 
| |_) | (_| | |_\__ \ | | | | | (_| | | | |
|_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_|
	Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Remember: While root can do most everything, there are certain
privileges that only a partner can grant.
	-- Telsa Gwynne