Using an instance variable inside a method

Hello.

I’m learning ruby 1.9 by reading the book “Programming Ruby 1.9
The Pragmatic Programmers’ Guide”

Actually i’m on the page 57 and i think something is wrong. Let’s show
the involved code :

#—

Excerpted from “Programming Ruby”,

published by The Pragmatic Bookshelf.

Copyrights apply to this code. It may not be used to create training

material,

courses, books, articles, and the like. Contact us if you are in

doubt.

We make no guarantees that this code is fit for any purpose.

Visit http://www.pragmaticprogrammer.com/titles/ruby3 for more book

information.
#—
class BookInStock

attr_reader :isbn
attr_accessor :price

def initialize(isbn, price)
@isbn = isbn
@price = Float(price)
end

def price_in_cents
Integer(price*100 + 0.5)
end

end
book = BookInStock.new(“isbn1”, 33.80)
puts “Price = #{book.price}”
puts “Price in cents = #{book.price_in_cents}”

About the method price_in_cents, i think it should be written like that
instead :

def price_in_cents
Integer(@price*100 + 0.5)
end

Simply because unless i’m really missing something, “price” is a class
attribute after all there, it seems that in this case the “@” is
implicit, but that doesn’t look the appropriate way to write it, right ?
Anyway i’ve tested with and without the “@”, the result is the same.

So is this a common practice in ruby or what ?

Thx for reading.

@price is an instance variable not a class variable ($price) I believe.

According to the book “$” is supposed to be used for global variables.
I still don’t get it :confused:

Quote from the book :

“There’s a common misconception, particularly among people who come from
languages
such as Java and C#, that the attr_reader declaration somehow declares
instance variables.
It doesn’t. It creates the accessor methods, but the variables
themselves don’t need to be
declared—they just pop into existence when you use them. Ruby completely
decouples
instance variables and accessor methods, as we’ll see in the section
Virtual Attributes on the
next page.”

The code involved is in this section, so it should be the key.
I just don’t understand why they didn’t write the “@”, maybe just to
prove what they said, but from my point of view it seems a bad practice.

$ = global
@@ = class
@ = instance

Ruby is clever enough to figure out that you mean self.price (using the
attr_accessor for @price) when you state “price” in the method. Of
course, you could create a local variable called “price” within that
code which would temporarily override the reference.

For example, modifying the class:

class BookInStock
def price_in_cents
price = 1
Integer(price*100 + 0.5)
end
end

book.price
=> 33.8
puts “Price in cents = #{book.price_in_cents}”
Price in cents = 100
=> nil
book.price
=> 33.8

I see, i thought that you could use these accessors only outside the
class, not inside it.
However i’m still not sure what’s the point of using the accessor
instead of directly the instance variable there.
I suppose it makes sense when a method shouldn’t use an instance
variable “as it is”.

Thx.

Personally I like to reference the instance variables using their “@”
form in order to avoid ambiguity in the code. Everyone has their own
approach and reasoning though, that’s one of the great things about
writing code… the artistic license :slight_smile:

On 6 February 2013 07:26, FirstName S. [email protected]
wrote:

I see, i thought that you could use these accessors only outside the
class, not inside it.
However i’m still not sure what’s the point of using the accessor
instead of directly the instance variable there.
I suppose it makes sense when a method shouldn’t use an instance
variable “as it is”.

Yeah, it’s a DRY thing.

If there’s no other logic in your accessor then @foo and self.foo
are
interchangeable (one has an extra character – more typing; the other in
theory has an extra function call – more execution time and memory
usage,
although this could well be optimised away for all I know.)

However if you have other code (assertions, last-minute coercions, etc.)
in
the accessor, then @foo and self.foo do different things, and you’d
have to make sure you either duplicate that code from self.foo (WETly)
or
be certain that you don’t need it in the case in question.

For myself, I use @foo when I’m thinking of the value as an instance
variable (literally a variable, some internal state used for
calculations
or whatever, private to the object’s scope), and self.foo when I’m
thinking of it as a “property” (an attribute that partially describes
the
object, visible to the outside world.)

As a general rule I try to avoid bare foo since it’s not clear whether
I
mean a local variable or a property of self or something else
altogether
(not to mention that self.foo = 1 is very different from foo = 1).

Incidentally, I didn’t realise the parser would recognise price above
as
a function call; I thought lexically it looked like a local variable.
Does
the attr_accessor directive make it more clever? Are attributes
lexically
different from function calls? Am I overthinking something?


Matthew K., B.Sc (CompSci) (Hons)
http://matthew.kerwin.net.au/
ABN: 59-013-727-651

“You’ll never find a programming language that frees
you from the burden of clarifying your ideas.” - xkcd

I’m certainly no expert on the Ruby interpreter, however I’d guess that
in order to support monkey-patching, multi file classes, and dynamic
dispatch/metaprogramming, the parser assumes that any part of the code
it can’t find at the moment of parsing may be defined somewhere else and
leaves it alone until run time. Just my guess.

-Ryan V.

On 2/5/13 7:59 PM, Matthew K. wrote:

Incidentally, I didn’t realise the parser would recognise price above
as a function call; I thought lexically it looked like a local variable.
Does the attr_accessor directive make it more clever? Are attributes
lexically different from function calls? Am I overthinking something?

On 6 February 2013 12:44, Ryan V. [email protected] wrote:

I’m certainly no expert on the Ruby interpreter, however I’d guess that
in order to support monkey-patching, multi file classes, and dynamic
dispatch/metaprogramming, the parser assumes that any part of the code it
can’t find at the moment of parsing may be defined somewhere else and
leaves it alone until run time. Just my guess.

Oh of course. If there’s no explicit variable creation (price = …) in
the current context, it has to assume it’s a function. Don’t mind me,
carry on.


Matthew K., B.Sc (CompSci) (Hons)
http://matthew.kerwin.net.au/
ABN: 59-013-727-651

“You’ll never find a programming language that frees
you from the burden of clarifying your ideas.” - xkcd

On Wed, Feb 6, 2013 at 5:20 AM, Student Jr [email protected] wrote:

The key here is “interpreter”. A bare token might either be a reference
to a local variable or to a method on self. The interpreter interprets
the code as it is being run. When it hits a bare token, it looks for a
method on self by that name. If found, it calls it. If not, it is
assumed to be a local variable.

This is not quite correct, although it’s close. Running Ruby code has
two steps, the parsing and the runtime. At parsing time, each token is
labeled as either a local variable or a method call. If the parser has
seen the token at the left hand side of an expression before, it
labels it as a local variable. If not, it labels it as a method call.
At runtime, tokens labeled as local variables are evaluated to their
value, and token labeled as methods are looked up the method execution
chain to find them.

Jesus.

Anyway i’m not a fan of implicit “not obvious” stuff, so i should write
“self.” rather than letting the interpreter guess.

Thx all, it’s pretty clear now.

The key here is “interpreter”. A bare token might either be a reference
to a local variable or to a method on self. The interpreter interprets
the code as it is being run. When it hits a bare token, it looks for a
method on self by that name. If found, it calls it. If not, it is
assumed to be a local variable.

And method bodies are definitely parsed ONLY when they are declared.
Interpretation waits. (Do not forget that ‘method =’ === ‘method=’ in
the method lookup.

Note that it does NOT try method_missing. This has major implications
if you are making heavy use of method_missing, as in TGWSNBN.

Using self.method is considered to be really bad form, unless you are
wanting method_missing to be invoked, in which case it is mandatory.
You see a lot of users of TGWSNBN writing junk like that.

As for attributes verses accessors, MK is doing it right. Just because
o.m is defined, and o has an attribute @m, there is no particular reason
to assume that o.m == o.instance_variable_get(:@m). There might be
important reasons that o.m = o.instance_variable_get(:@m) * 100 or
whatever.

On Thu, Feb 7, 2013 at 1:56 AM, Student Jr [email protected] wrote:

Actually, there is another reason to avoid self.method. self.method has
the security level of protected

Right! Sometimes this is used intentionally to make method calls look
more like keywords - “attr_accessor” is such a case:

irb(main):006:0> Module.private_instance_methods.grep /attr/
=> [:attr, :attr_reader, :attr_writer, :attr_accessor]

–you can only access private methods via
self.send. Just say no.

There are two ways to invoke private methods

foo()
self.send(:foo)

Note that the second also works with other expressions than “self”.

Kind regards

robert

Actually, there is another reason to avoid self.method. self.method has
the security level of protected–you can only access private methods via
self.send. Just say no.

And is sounds like Jesus has actually worked with deep documentation. :slight_smile:

ernie n. wrote in post #1105353:

Why can I access p[6] without the “@” within the class? I’ve run this
in pry/irb and the p array looks the same regardless how I reference it

  • either @p or p. What’s up here?

@p references the instance variable, and bare p is a method call.

attr_accessor :p defines a method called p which returns @p *

Thus, your p[6].. code is parsed as a method call (self.p)[6]..,
which is legal because that method (self.p) exists.


  • note: it also defines a method called p= which assigns to @p, so
    you can use p = [] instead of @p = [] if you want. C.f. attr_reader
    and attr_writer

On Apr 11, 2013, at 21:38 , Matthew K. [email protected] wrote:

  • note: it also defines a method called p= which assigns to @p, so
    you can use p = [] instead of @p = [] if you want. C.f. attr_reader
    and attr_writer

No. you can use self.p = [], not p = []. That’s the gotcha because
the latter is treated as a local variable assign.

On Fri, Apr 12, 2013 at 10:37 AM, Ryan D.
[email protected]wrote:

On Apr 11, 2013, at 21:38 , Matthew K. [email protected] wrote:

  • note: it also defines a method called p= which assigns to @p, so
    you can use p = [] instead of @p = [] if you want. C.f. attr_reader
    and attr_writer

No. you can use self.p = [], not p = []. That’s the gotcha because the
latter is treated as a local variable assign.

One more remark: it’s probably not too good to name an attribute “p”
because the accessor will hide method “p” which is used for debug
printing.
Also, the name “p” doesn’t really reveal any semantics. I usually
restrict those names to internal use only but use more telling names for
public APIs.

Kind regards

robert

I’m a couple weeks as a Ruby newby … writing a fun puzzle and ran into
an issue I don’t understand (read lots of books and searched …).

class Board
attr_accessor :type, :b, :p, :audit

def initialize(type)
@audit = Array.new
@type = type # either 9 or 10 depending on puzzle type!
@b = Hash.new(:OOB) # default for OOB
@p = Array.new # position of all the Pieces within the block
if(type == 9)
p[6] = Piece.new(6,1,1,:Obt)
p[7] = Piece.new(7,2,1,:Obt)
else

Why can I access p[6] without the “@” within the class? I’ve run this
in pry/irb and the p array looks the same regardless how I reference it

  • either @p or p. What’s up here?

Thx