Including instance methods and setting an instance variable

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/.

Hi --

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

···

On Fri, 21 Mar 2008, Leon Bogaert wrote:

--
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!

Thanks for the clear explanation David!

Going to try some more.

Leon

···

--
Posted via http://www.ruby-forum.com/.

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/.

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

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
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
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
irb(main):008:0>

Kind regards

  robert

···

On 21.03.2008 11:15, Leon Bogaert wrote:
         from :0

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? :slight_smile:

···

--
Posted via http://www.ruby-forum.com/.

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/.

Hi --

This guy: How to add a instance variable through a mixin? - Ruby - Ruby-Forum
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 :slight_smile:

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

···

On Sat, 22 Mar 2008, Leon Bogaert wrote:

--
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!

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/.

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. :slight_smile:

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

···

On 22.03.2008 09:34, Leon Bogaert wrote:

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

···

On Sat, Mar 22, 2008 at 11:34 AM, Robert Klemme <shortcutter@googlemail.com> 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

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

---
Whereof one cannot speak, thereof one must be silent.
Ludwig Wittgenstein

> 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. :slight_smile:

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. :slight_smile:

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

···

On 22.03.2008 13:43, Robert Dober wrote:

On Sat, Mar 22, 2008 at 11:34 AM, Robert Klemme > <shortcutter@googlemail.com> wrote:

On 22.03.2008 09:34, Leon Bogaert wrote:

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.

···

On 3/22/08, Robert Klemme <shortcutter@googlemail.com> 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

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

> I am very confused by this thread

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

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 :wink:

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 :wink:

···

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

---
Whereof one cannot speak, thereof one must be silent.
Ludwig Wittgenstein

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. :slight_smile:

Kind regards

  robert

···

On 22.03.2008 14:31, Rick DeNatale wrote:

On 3/22/08, Robert Klemme <shortcutter@googlemail.com> 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.

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.

···

On 3/22/08, Robert Dober <robert.dober@gmail.com> wrote:

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

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 :wink:

R.

···

On Sat, Mar 22, 2008 at 7:42 PM, Rick DeNatale <rick.denatale@gmail.com> wrote:
--
http://ruby-smalltalk.blogspot.com/

---
Whereof one cannot speak, thereof one must be silent.
Ludwig Wittgenstein

Well there is an RSS feed <G>

···

On 3/22/08, Robert Dober <robert.dober@gmail.com> wrote:

On Sat, Mar 22, 2008 at 7:42 PM, Rick DeNatale <rick.denatale@gmail.com> 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 :wink:

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

>
> > 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 :wink:

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.

···

On Sat, Mar 22, 2008 at 10:50 PM, Rick DeNatale <rick.denatale@gmail.com> wrote:

On 3/22/08, Robert Dober <robert.dober@gmail.com> wrote:
> On Sat, Mar 22, 2008 at 7:42 PM, Rick DeNatale <rick.denatale@gmail.com> wrote:

--
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

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

···

On 22.03.2008 23:09, Robert Dober wrote:

On Sat, Mar 22, 2008 at 10:50 PM, Rick DeNatale <rick.denatale@gmail.com> wrote:

On 3/22/08, Robert Dober <robert.dober@gmail.com> wrote:

On Sat, Mar 22, 2008 at 7:42 PM, Rick DeNatale <rick.denatale@gmail.com> 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 :wink:

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