# Basic mistake?

**URL:** <https://www.ruby-forum.com/t/basic-mistake/76138>\
**Category:** Ruby\
**Created:** [November 16, 2006, 6:16am UTC](https://www.ruby-forum.com/t/basic-mistake/76138 "2006-11-16T06:16:44Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Nia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/8dc957/32.png) [@Nia](https://www.ruby-forum.com/u/Nia)\
**Post date:** [November 16, 2006, 6:16am UTC](https://www.ruby-forum.com/t/basic-mistake/76138/1 "2006-11-16T06:16:44Z")

</div>

* * *

class BookStore  
@bookstore=Array.new

def initialize(\*books)  
i=0  
books.each do |x|  
#@bookstore.push(x)  
puts “(#{i})” + x.inspect  
i+=1  
end  
end  
end

class Book  
def initialize(name,cost)  
@book\_name=name  
@book\_cost=cost  
end

def detail  
puts “Book: #{@book\_name} ($#{@book\_cost})”  
end  
end

b1=Book.new(‘Harry Potter’,‘9.95’)  
b2=Book.new(‘The Raven’,‘8.65’)  
store = BookStore.new(b1,b2)

---

<div class="post-metadata">

**Author:** ![Nia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/8dc957/32.png) [@Nia](https://www.ruby-forum.com/u/Nia)\
**Post date:** [November 16, 2006, 6:22am UTC](https://www.ruby-forum.com/t/basic-mistake/76138/2 "2006-11-16T06:22:44Z")

</div>

Nia wrote:

> ```
> end
> puts "Book: #{@book_name} ($#{@book_cost})"
> 
> ```
> 
> the first time i’ve encounter this problem. please help me solve it.

At least two mistakes here… move the @bookstore line  
down into the initialize method. And take off the #  
from that line – that makes it a comment.

Hal

---

<div class="post-metadata">

**Author:** ![Nia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/8dc957/32.png) [@Nia](https://www.ruby-forum.com/u/Nia)\
**Post date:** [November 16, 2006, 7:14am UTC](https://www.ruby-forum.com/t/basic-mistake/76138/3 "2006-11-16T07:14:48Z")

</div>

On Thu, 16 Nov 2006 14:21:21 +0900  
Hal F. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > ```
> > i+=1
> > 
> > ```
> > 
> > def detail  
> > seem to work fine outside of a class. am i missing something?, like a declaration? this isn’t

You can also consolidate part of the initialize method like so:  
def initialize(\*books)  
@bookstore=Array.new  
books.each\_with\_index do |x,i|  
@bookstore.push(x)  
puts “(#{i})” + x.inspect  
end  
end

---

<div class="post-metadata">

**Author:** ![Nia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/8dc957/32.png) [@Nia](https://www.ruby-forum.com/u/Nia)\
**Post date:** [November 16, 2006, 2:19pm UTC](https://www.ruby-forum.com/t/basic-mistake/76138/4 "2006-11-16T14:19:48Z")

</div>

Hal F. schrieb:

> > ```
> > end
> > 
> > ```
> > 
> > end  
> > isn’t the first time i’ve encounter this problem. please help me  
> > solve it.
> 
> At least two mistakes here… move the @bookstore line  
> down into the initialize method. And take off the #  
> from that line – that makes it a comment.  
> Which is what (s)he intentionally did (“i commented it out since it  
> wasn’t working”) 😉  
> Hal  
> Robert

---

<div class="post-metadata">

**Author:** ![Nia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/8dc957/32.png) [@Nia](https://www.ruby-forum.com/u/Nia)\
**Post date:** [November 16, 2006, 3:11pm UTC](https://www.ruby-forum.com/t/basic-mistake/76138/5 "2006-11-16T15:11:55Z")

</div>

Robert S. wrote:

> > > ```
> > > i+=1
> > > end
> > > 
> > > ```
> > > 
> > > end  
> > > end  
> > > …

Hal is correct, moving it into initialize solves the problem.

It appears that declaring the instance variable at the class  
level makes it an instance variable of the class, rather than  
of the object of the class being created when initialize is called.

In short, declare your instance attributes inside initialize.

Cheers  
Chris

---

<div class="post-metadata">

**Author:** ![Nia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/8dc957/32.png) [@Nia](https://www.ruby-forum.com/u/Nia)\
**Post date:** [November 16, 2006, 5:16pm UTC](https://www.ruby-forum.com/t/basic-mistake/76138/6 "2006-11-16T17:16:35Z")

</div>

> 

hehe, i knew it was some basic mistake. thank you all very much. so is  
it wrong to declare a  
variable outside a method? cause i usually do that a lot,

---

<div class="post-metadata">

**Author:** ![Nia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/8dc957/32.png) [@Nia](https://www.ruby-forum.com/u/Nia)\
**Post date:** [November 16, 2006, 5:26pm UTC](https://www.ruby-forum.com/t/basic-mistake/76138/7 "2006-11-16T17:26:38Z")

</div>

Hi –

On Fri, 17 Nov 2006, Nia wrote:

> > 
> 
> hehe, i knew it was some basic mistake. thank you all very much. so  
> is it wrong to declare a variable outside a method? cause i usually  
> do that a lot,

It’s wrong to initialize a variable in one scope and try to use it in  
another 🙂 Actually there are (at least) two things to keep in mind:

1. Local variables are visible in their local scope. So here:

the two x’s are totally unrelated.

1. Instance variables are scoped to, or associated with, “self”. In  
other words, an instance variable (@var) always belongs to whatever  
object is “self” at that point. Here:

you’re dealing with two selfs (selves?). At (a), self is the class  
object itself, C. At (b), self will be whatever instance of C calls  
the methods “meth”. So, since there are two selfs, the two @x’s are  
totally unrelated to each other.

David

---

<div class="post-metadata">

**Author:** ![Nia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/8dc957/32.png) [@Nia](https://www.ruby-forum.com/u/Nia)\
**Post date:** [November 16, 2006, 5:54pm UTC](https://www.ruby-forum.com/t/basic-mistake/76138/8 "2006-11-16T17:54:42Z")

</div>

On 11/16/06, Nia [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> so is it wrong to declare a  
> variable outside a method? cause i usually do that a lot,

This misunderstanding probably stems from the following type of code:

# NOTE: no enclosing class

@a = “foo” # (a)  
def bar  
puts @a # (b)  
end  
bar # =\> prints “foo”

Se _here_, the @a seems to be able to stretch across the method  
definition. Why?

The reason is because all “procedural” (top level scope) code is  
invoked in the context of the “main” object. At (a), self is “main”,  
so @a belongs to the “main” object. When you define methods in context  
of the “main” object those methods are actually created as instance  
methods on Object, which makes them available everywhere (since every  
object in Ruby is\_a? Object). So the @a at (b) refers to the @a of  
whoever calls bar. At (c), “main” is calling bar, so its value of @a  
(set at (a)) is used.

Let’s try calling bar from the context of an object that doesn’t have @a  
set:

@a = “foo” # belongs to “main”

def bar  
puts(@a || “@a is empty!”)  
end

bar # =\> prints “foo”

module A  
# “self” here is the module itself  
bar # =\> prints “@a is empty!”  
end

So, the moral? The above construct where you have @a defined at the  
top level and then (tried) to use in a top level method only works by  
accident. While it works in the common case where used, it’s not  
correct and can lead to errors when the top level method is called in  
a context _other_ than the top level. If you _really_ need that sort  
of behavior, use globals ($a). That’s what they’re for. But, of  
course, if you find yourself needing globals you probably want to  
rethink your approach. 🙂

Hope that made sense…

Jacob F.
