including instance methods and setting an instance variable

Discussion in 'Ruby' started by Leon Bogaert, Mar 20, 2008.

  1. Leon Bogaert

    Leon Bogaert Guest

    Hi all,

    I'm trying to include a module and in that module I want to set an
    instance variable. I have the following:

    class Queue
    include LBo::InstanceMethods
    end

    module LBo
    module InstanceMethods
    attr_accessor :position
    self.position = 1
    end
    end

    q = Queue.new
    q.position

    But I'm getting this error:
    undefined method `position=' for LBo::InstanceMethods:Module
    (NoMethodError)

    I'm feeling like a moron because I can't understand why this is not
    working.
    I tried setting the @position variable directly, but when I do
    q.position it gives back nil.

    Could somebody lend me a hand with this one?

    Thanks in advance!
    --
    Posted via http://www.ruby-forum.com/.
     
    Leon Bogaert, Mar 20, 2008
    #1
    1. Advertising

  2. Hi --

    On Fri, 21 Mar 2008, Leon Bogaert wrote:

    > Hi all,
    >
    > I'm trying to include a module and in that module I want to set an
    > instance variable. I have the following:
    >
    > class Queue
    > include LBo::InstanceMethods
    > end
    >
    > module LBo
    > module InstanceMethods
    > attr_accessor :position
    > self.position = 1


    self at this point is the Module object LBo::InstanceMethods. You're
    calling the #position method on that Module object.

    > end
    > end
    >
    > q = Queue.new
    > q.position
    >
    > But I'm getting this error:
    > undefined method `position=' for LBo::InstanceMethods:Module
    > (NoMethodError)


    See above.

    > I'm feeling like a moron because I can't understand why this is not
    > working.
    > I tried setting the @position variable directly, but when I do
    > q.position it gives back nil.
    >
    > Could somebody lend me a hand with this one?


    It's mostly about 'self'. You have to be aware of what self is when
    you use it. Inside a module definition, it's the Module object itself.
    Inside an instance method, it's the instance.

    The job of the module is (mainly) to define instance methods that will
    be executed by objects yet unborn. The module itself has no direct
    access to the instance variables of those objects. But it can define
    methods that do things with them.

    For example:

    module LBo
    module InstanceMethods
    attr_writer :position
    def position
    @position ||= 1
    end
    end
    end

    class C
    include LBo::InstanceMethods
    end

    C.new.position # 1

    Here, I'm writing an instance method #position, which when executed
    with a C instance as 'self' will set the appropriate instance
    variable if that variable isn't set already.


    David

    --
    Upcoming Rails training from David A. Black and Ruby Power and Light:
    ADVANCING WITH RAILS, April 14-17 2008, New York City
    CORE RAILS, June 24-27 2008, London (Skills Matter)
    See http://www.rubypal.com for details. Berlin dates coming soon!
     
    David A. Black, Mar 21, 2008
    #2
    1. Advertising

  3. Leon Bogaert

    Leon Bogaert Guest

    Re: including instance methods and setting an instance varia

    Thanks for the clear explanation David!

    Going to try some more.

    Leon
    --
    Posted via http://www.ruby-forum.com/.
     
    Leon Bogaert, Mar 21, 2008
    #3
  4. Leon Bogaert

    Leon Bogaert Guest

    Re: including instance methods and setting an instance varia

    Can I "connect" with the instance if it get's instanciated? Because I
    wanted to do something like:

    if not self.respond_to? :each
    return false
    end

    Thanks!
    --
    Posted via http://www.ruby-forum.com/.
     
    Leon Bogaert, Mar 21, 2008
    #4
  5. Re: including instance methods and setting an instance varia

    On 21.03.2008 11:15, Leon Bogaert wrote:
    > Can I "connect" with the instance if it get's instanciated? Because I
    > wanted to do something like:
    >
    > if not self.respond_to? :each
    > return false
    > end


    The bit above can be shortened to

    return false unless respond_to? :each


    There are at least these three options:

    1. do not check at all

    This is my preferred solution, as it is the simplest and works well.

    irb(main):001:0> class Foo
    irb(main):002:1> include Enumerable
    irb(main):003:1> end
    => Foo
    irb(main):004:0> f=Foo.new
    => #<Foo:0x7ff8bff4>
    irb(main):005:0> f.map {|x| x+1}
    NoMethodError: undefined method `each' for #<Foo:0x7ff8bff4>
    from (irb):5:in `map'
    from (irb):5
    from :0

    2. check on the class level, this should generally be sufficient

    irb(main):001:0> module Checker
    irb(main):002:1> def self.included(cl)
    irb(main):003:2> cl.instance_method :each
    irb(main):004:2> end
    irb(main):005:1> end
    => nil
    irb(main):006:0> class Baz
    irb(main):007:1> include Checker
    irb(main):008:1> end
    NameError: undefined method `each' for class `Baz'
    from (irb):3:in `instance_method'
    from (irb):3:in `included'
    from (irb):7:in `include'
    from (irb):7
    from :0
    irb(main):009:0> Baz
    => Baz
    irb(main):010:0> Baz.ancestors
    => [Baz, Checker, Object, Kernel]
    irb(main):011:0>

    Note that even the exception does not prevent inclusion. But you can
    react on this and define the method for example.


    3. on instantiation, in this case you need to be in the inheritance chain

    irb(main):001:0> module Checker
    irb(main):002:1> def initialize(*a,&b)
    irb(main):003:2> method :each
    irb(main):004:2> end
    irb(main):005:1> end
    => nil
    irb(main):006:0> class Foo
    irb(main):007:1> include Checker
    irb(main):008:1> def initialize
    irb(main):009:2> super
    irb(main):010:2> end
    irb(main):011:1> end
    => nil
    irb(main):012:0> Foo.new
    NameError: undefined method `each' for class `Foo'
    from (irb):3:in `method'
    from (irb):3:in `initialize'
    from (irb):9:in `initialize'
    from (irb):12:in `new'
    from (irb):12
    from :0
    irb(main):013:0>


    4. check when individual objects are extended

    irb(main):001:0> module Checker
    irb(main):002:1> def self.extended(o)
    irb(main):003:2> o.method :each
    irb(main):004:2> end
    irb(main):005:1> end
    => nil
    irb(main):006:0> x = Object.new
    => #<Object:0x7ff89f4c>
    irb(main):007:0> x.extend Checker
    NameError: undefined method `each' for class `Object'
    from (irb):3:in `method'
    from (irb):3:in `extended'
    from (irb):7:in `extend'
    from (irb):7
    from :0
    irb(main):008:0>


    Kind regards

    robert
     
    Robert Klemme, Mar 21, 2008
    #5
  6. Leon Bogaert

    Leon Bogaert Guest

    Re: including instance methods and setting an instance varia

    Thanks Robert!

    So it is *never* possible to set an instance variable via a mixin?
    Except of course, via a method that gets run when the, uhm..., stuff has
    transformed into an object? :)
    --
    Posted via http://www.ruby-forum.com/.
     
    Leon Bogaert, Mar 21, 2008
    #6
  7. Leon Bogaert

    Leon Bogaert Guest

    Re: including instance methods and setting an instance varia

    This guy: http://www.ruby-forum.com/topic/142444
    had the same question as me. Reading that post made things a lot
    clearer.

    It's difficult to apprehend how this stuff works in Ruby. Especially if
    you read some stuff like instance_eval and the lot.
    --
    Posted via http://www.ruby-forum.com/.
     
    Leon Bogaert, Mar 21, 2008
    #7
  8. Re: including instance methods and setting an instance varia

    Hi --

    On Sat, 22 Mar 2008, Leon Bogaert wrote:

    > This guy: http://www.ruby-forum.com/topic/142444
    > had the same question as me. Reading that post made things a lot
    > clearer.
    >
    > It's difficult to apprehend how this stuff works in Ruby. Especially if
    > you read some stuff like instance_eval and the lot.


    It's not that hard; it's all based on a small number of principles
    that never change.

    1. Some object is always "self"
    2. Every instance variable belongs to "self"
    3. obj.instance_eval {...} temporarily (for the duration of the code
    block) sets self to obj.

    The hardest one seems to be #2. But it makes sense once you realize
    that there is *always* a "self". So when you see this:

    module M
    @x = 1
    def my_method
    @x = 1
    end
    end

    you're seeing two "self" contexts: the outer level of the module
    definition (where self is M) and the inside of the method definition
    (where self is, or rather will be, whatever object calls my_method.
    Therefore, the two "@x"s have nothing whatsoever to do with each
    other.

    I should add:

    4. Classes and modules are objects

    which is, as I'm fond of saying to my trainees, the answer to about
    75% of all questions about Ruby :)

    You also have to keep in mind that self is not the same as local
    scope. self changes, and local scope changes, but not always in sync
    with each other. They're two different things.


    David

    --
    Upcoming Rails training from David A. Black and Ruby Power and Light:
    ADVANCING WITH RAILS, April 14-17 2008, New York City
    CORE RAILS, June 24-27 2008, London (Skills Matter)
    See http://www.rubypal.com for details. Berlin dates coming soon!
     
    David A. Black, Mar 21, 2008
    #8
  9. Leon Bogaert

    Leon Bogaert Guest

    Re: including instance methods and setting an instance varia

    Ah thanks David.

    And that's of course why

    Module X
    instance_eval do
    @testing = [1,2,3]
    end
    end

    String.new('test').include(X)

    will never work. Because you can't get self to become the instantiated
    object.
    --
    Posted via http://www.ruby-forum.com/.
     
    Leon Bogaert, Mar 22, 2008
    #9
  10. Re: including instance methods and setting an instance varia

    On 22.03.2008 09:34, Leon Bogaert wrote:
    > Ah thanks David.
    >
    > And that's of course why
    >
    > Module X
    > instance_eval do
    > @testing = [1,2,3]
    > end
    > end


    This sets an instance variable of X.

    > String.new('test').include(X)


    'test'.include X

    This is sufficient, because "" and '' are object constructors:

    irb#1(main):001:0> 3.times { puts "foo".object_id }
    1073547530
    1073547510
    1073547490
    => 3

    > will never work. Because you can't get self to become the instantiated
    > object.


    Which is kind of obvious because the object does not even exist when you
    define the module. :)

    If you want a module to manipulate instance variables you do it the same
    way as with ordinary class instance methods. The major difference is
    that it's harder to initialize them during object creation because the
    class needs to cooperate (calling super in #initialize). The more
    robust approach is to assume that they are not initialized as David has
    shown in his example with @position.

    Kind regards

    robert
     
    Robert Klemme, Mar 22, 2008
    #10
  11. Leon Bogaert

    Robert Dober Guest

    Re: including instance methods and setting an instance varia

    On Sat, Mar 22, 2008 at 11:34 AM, Robert Klemme
    <> wrote:
    > On 22.03.2008 09:34, Leon Bogaert wrote:
    > > Ah thanks David.
    > >
    > > And that's of course why
    > >
    > > Module X
    > > instance_eval do
    > > @testing = [1,2,3]
    > > end
    > > end

    >
    > This sets an instance variable of X.
    >
    >
    > > String.new('test').include(X)

    >
    > 'test'.include X

    Do you mean extend?
    And if so what good would that do, even if we had a reference to test
    as the module does not define any methods.

    I am very confused by this thread but somehow have the feeling that OP
    wants this

    module X
    def set
    @x=[*1..3]
    end
    end
    class C
    attr_reader :x
    include X
    end
    c=C.new
    c.set
    p c.x

    and might get confused by
    a='test'.extend X
    a.set
    p a.instance_variable_get("@x")

    but at least it clearly shows that the included or extended method
    that was defined in a module does precisely what OP doubted possible:
    Accessing ivars.

    HTH
    Robert


    --
    http://ruby-smalltalk.blogspot.com/

    ---
    Whereof one cannot speak, thereof one must be silent.
    Ludwig Wittgenstein
     
    Robert Dober, Mar 22, 2008
    #11
  12. Re: including instance methods and setting an instance varia

    On 22.03.2008 13:43, Robert Dober wrote:
    > On Sat, Mar 22, 2008 at 11:34 AM, Robert Klemme
    > <> wrote:
    >> On 22.03.2008 09:34, Leon Bogaert wrote:
    >> > Ah thanks David.
    >> >
    >> > And that's of course why
    >> >
    >> > Module X
    >> > instance_eval do
    >> > @testing = [1,2,3]
    >> > end
    >> > end

    >>
    >> This sets an instance variable of X.
    >>
    >>
    >> > String.new('test').include(X)

    >>
    >> 'test'.include X

    > Do you mean extend?


    You are right, my answer was too short. The bit I showed is indeed
    equivalent to the original - however both are dysfunctional. :)

    > And if so what good would that do, even if we had a reference to test
    > as the module does not define any methods.


    My point was that String.new "foo" is superfluous because "foo" does
    already create a new object.

    > I am very confused by this thread


    Please don't. I would feel sorry to have caused confusion. :)

    > but somehow have the feeling that OP
    > wants this


    Actually we (I) do not exactly now what the OP exactly wants to do. So
    far I know only that he wants to access instance variables from a
    module. I am guessing that he thinks it's somehow different than from
    class instance methods. But it isn't (apart from the initialization
    story, see previous posting).

    A small addition: modules are a nice case where accessing instance
    variables via accessor methods instead of directly pays off because then
    you can centralize initialization:

    # a bit silly example
    module ItemManager
    def items
    @items ||= []
    end

    def add(item)
    items << item
    end

    def delete(item)
    items.delete item
    end

    def reorder
    items.sort!
    end
    end

    > but at least it clearly shows that the included or extended method
    > that was defined in a module does precisely what OP doubted possible:
    > Accessing ivars.


    Correct.

    Happy Easter

    robert
     
    Robert Klemme, Mar 22, 2008
    #12
  13. Re: including instance methods and setting an instance varia

    On 3/22/08, Robert Klemme <> wrote:

    > A small addition: modules are a nice case where accessing instance
    > variables via accessor methods instead of directly pays off because then
    > you can centralize initialization:
    >
    > # a bit silly example
    > module ItemManager
    > def items
    > @items ||= []
    > end


    I'd say that this defers rather than centralizes initialization. In
    fact it might be said that it decentralizes it, since the
    initialization of such instance variables don't occur in an initialize
    method.

    That's not a criticism. This is a form of the lazy initialization
    pattern which is common in dynamic languages. The neat thing about
    ruby is that the instance variables don't even exist until they are
    needed, unlike in languages like Smalltalk where they need to be
    pre-declared in the class definition.

    I'm reminded that there used to be a tendency among some Smalltalkers
    to call this "laissez faire" initialization, which would be an
    entirely different thing I think. This just showed a lack of
    knowledge of French, and the use of this phrase instead of lazy
    initialization was one of Ralph Johnson's pet peeves IIRC.

    --
    Rick DeNatale

    My blog on Ruby
    http://talklikeaduck.denhaven2.com/
     
    Rick DeNatale, Mar 22, 2008
    #13
  14. Re: including instance methods and setting an instance varia

    On 22.03.2008 14:31, Rick DeNatale wrote:
    > On 3/22/08, Robert Klemme <> wrote:
    >
    >> A small addition: modules are a nice case where accessing instance
    >> variables via accessor methods instead of directly pays off because then
    >> you can centralize initialization:
    >>
    >> # a bit silly example
    >> module ItemManager
    >> def items
    >> @items ||= []
    >> end

    >
    > I'd say that this defers rather than centralizes initialization. In
    > fact it might be said that it decentralizes it, since the
    > initialization of such instance variables don't occur in an initialize
    > method.


    I can see what you mean, but it is still in a *single* and hence central
    location. The alternative would be to spread the @items ||= [] all over
    the methods defined in the module (maybe I should've mentioned that in
    the first place). It's not as central as #initialize since that method
    is /usually/ (nut not always) used to initialize an object's state
    though, so I can 45% agree - but also have to 55% disagree. :)

    Kind regards

    robert
     
    Robert Klemme, Mar 22, 2008
    #14
  15. Leon Bogaert

    Robert Dober Guest

    Re: including instance methods and setting an instance varia

    > > I am very confused by this thread
    >
    > Please don't. I would feel sorry to have caused confusion. :)

    No not your post, I meant what OP really meant, but see below...
    >
    >
    > > but somehow have the feeling that OP
    > > wants this

    >
    > Actually we (I) do not exactly now what the OP exactly wants to do.

    That's what I meant above ;)
    > So
    > far I know only that he wants to access instance variables from a
    > module. I am guessing that he thinks it's somehow different than from
    > class instance methods. But it isn't (apart from the initialization
    > story, see previous posting).

    That is the key sentence he should read I agree, and Rick's technique
    is often useful in doing so especially
    in cases where the Mixin does not mix #initialize in (does not define
    a method initialize).
    >
    > A small addition: modules are a nice case where accessing instance
    > variables via accessor methods instead of directly pays off because then
    > you can centralize initialization:

    Yup; I all invite you to read Ricks Blog he wrote a great summary of
    that "pattern" on his Blog.
    Did you have problems with spam Rick, as comments are disabled? Wanted
    to tell you how much I enjoyed the read, I honestly
    think it is a valuable addition to what Kent says in the book.
    <snip>
    > Happy Easter

    Idem
    >
    > robert

    Idem ;)
    >
    >




    --
    http://ruby-smalltalk.blogspot.com/

    ---
    Whereof one cannot speak, thereof one must be silent.
    Ludwig Wittgenstein
     
    Robert Dober, Mar 22, 2008
    #15
  16. Re: including instance methods and setting an instance varia

    On 3/22/08, Robert Dober <> wrote:

    > Yup; I all invite you to read Ricks Blog he wrote a great summary of
    > that "pattern" on his Blog.


    Thanks.

    > Did you have problems with spam Rick, as comments are disabled? Wanted
    > to tell you how much I enjoyed the read, I honestly
    > think it is a valuable addition to what Kent says in the book.


    I've got it set up to disable comments once an article is 30 days old.

    Before that comments are moderated.

    --
    Rick DeNatale

    My blog on Ruby
    http://talklikeaduck.denhaven2.com/
     
    Rick DeNatale, Mar 22, 2008
    #16
  17. Leon Bogaert

    Robert Dober Guest

    Re: including instance methods and setting an instance varia

    On Sat, Mar 22, 2008 at 7:42 PM, Rick DeNatale <> wrote:

    > I've got it set up to disable comments once an article is 30 days old.

    Point taken, I really should step by more frequently ;)
    >

    R.
    --
    http://ruby-smalltalk.blogspot.com/

    ---
    Whereof one cannot speak, thereof one must be silent.
    Ludwig Wittgenstein
     
    Robert Dober, Mar 22, 2008
    #17
  18. Re: including instance methods and setting an instance varia

    On 3/22/08, Robert Dober <> wrote:
    > On Sat, Mar 22, 2008 at 7:42 PM, Rick DeNatale <> wrote:
    >
    > > I've got it set up to disable comments once an article is 30 days old.

    >
    > Point taken, I really should step by more frequently ;)


    Well there is an RSS feed <G>

    --
    Rick DeNatale

    My blog on Ruby
    http://talklikeaduck.denhaven2.com/
     
    Rick DeNatale, Mar 22, 2008
    #18
  19. Leon Bogaert

    Robert Dober Guest

    Re: including instance methods and setting an instance varia

    On Sat, Mar 22, 2008 at 10:50 PM, Rick DeNatale <> wrote:
    > On 3/22/08, Robert Dober <> wrote:
    >
    > > On Sat, Mar 22, 2008 at 7:42 PM, Rick DeNatale <> wrote:
    > >
    > > > I've got it set up to disable comments once an article is 30 days old.

    > >
    > > Point taken, I really should step by more frequently ;)

    >
    > Well there is an RSS feed <G>

    Ah I have heard of that (RSS) already, I will try to let Firefox, work
    it out :-0
    R.
    >
    >
    >
    > --
    > Rick DeNatale
    >
    > My blog on Ruby
    > http://talklikeaduck.denhaven2.com/
    >
    >




    --
    http://ruby-smalltalk.blogspot.com/

    ---
    Whereof one cannot speak, thereof one must be silent.
    Ludwig Wittgenstein
     
    Robert Dober, Mar 22, 2008
    #19
  20. [OT] RSS Reader (was: Re: including instance methods and settingan instance varia)

    On 22.03.2008 23:09, Robert Dober wrote:
    > On Sat, Mar 22, 2008 at 10:50 PM, Rick DeNatale <> wrote:
    >> On 3/22/08, Robert Dober <> wrote:
    >>
    >>> On Sat, Mar 22, 2008 at 7:42 PM, Rick DeNatale <> wrote:
    >> >
    >> > > I've got it set up to disable comments once an article is 30 days old.
    >> >
    >> > Point taken, I really should step by more frequently ;)

    >>
    >> Well there is an RSS feed <G>

    > Ah I have heard of that (RSS) already, I will try to let Firefox, work
    > it out :-0


    Frankly, I would not do that. In fact, I have tried it but FF's RSS
    reading is pretty awkward IMHO. I prefer Google's RSS reader or
    NewsGator because they have the advantage to be webbased and are so good
    suited when you change systems frequently. My 0.02 EUR.

    Kind regards

    robert
     
    Robert Klemme, Mar 23, 2008
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Neo
    Replies:
    1
    Views:
    531
    Scott Allen
    Jan 7, 2005
  2. John M. Gabriele
    Replies:
    18
    Views:
    1,174
    Steven Bethard
    Feb 18, 2005
  3. arose
    Replies:
    2
    Views:
    147
    arose
    Jun 9, 2006
  4. Vincent Fourmond

    Modules, instance methods and class methods

    Vincent Fourmond, Sep 26, 2006, in forum: Ruby
    Replies:
    5
    Views:
    161
    Trans
    Sep 27, 2006
  5. Kenneth McDonald
    Replies:
    5
    Views:
    342
    Kenneth McDonald
    Sep 26, 2008
Loading...

Share This Page