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.

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

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

···

On Tue, Feb 5, 2013 at 12:17 PM, FirstName Surname <lists@ruby-forum.com>wrote:

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.

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

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.

···

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

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

···

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

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.

···

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

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:

···

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

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

···

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

Anyway i'm not a fan of implicit "not obvious" stuff, so i should write
"self."

Thx all, it's pretty clear now.

···

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

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:

···

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

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

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

The code is correct, however I see how it could be confusing.

BookInStock#price is an attribute of the BookInStock instance. This is
defined by the "attr_accessor :price" line, which essentially defines
two methods for you:

def price
  @price
end

def price= value
  @price = value
end

The line you're questioning uses the automatically created accessor
method, hence your confusion. It is arguable which method is more
correct, however.

Hopefully that clears it up,
Ryan Victory

···

On 2/5/13 2:26 PM, Colby Callahan wrote:

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

On Tue, Feb 5, 2013 at 12:17 PM, FirstName Surname > <lists@ruby-forum.com <mailto:lists@ruby-forum.com>> wrote:

    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.

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

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?

···

On 6 February 2013 07:26, FirstName Surname <lists@ruby-forum.com> 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".

--
  Matthew Kerwin, 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

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.

···

On Wed, Feb 6, 2013 at 5:20 AM, Student Jr <lists@ruby-forum.com> 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.

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

···

On Thu, Feb 7, 2013 at 1:56 AM, Student Jr <lists@ruby-forum.com> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

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

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

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 Victory

···

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

On 6 February 2013 07:26, FirstName Surname <lists@ruby-forum.com > <mailto:lists@ruby-forum.com>> 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 Kerwin, 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

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

···

On Apr 11, 2013, at 21:38 , Matthew Kerwin <lists@ruby-forum.com> 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

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.

···

On 2/5/13 7:59 PM, Matthew Kerwin 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 Victory <ryan@raptormail.net> 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.

--
  Matthew Kerwin, 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

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

···

On Fri, Apr 12, 2013 at 10:37 AM, Ryan Davis <ryand-ruby@zenspider.com>wrote:

On Apr 11, 2013, at 21:38 , Matthew Kerwin <lists@ruby-forum.com> 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.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/