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.
@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.
According to the book "$" is supposed to be used for global variables.
I still don't get it
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.
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
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".
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
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.
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.
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?
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.
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".
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.
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
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?
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.
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.