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.
on 2013-02-05 21:17
on 2013-02-05 21:43
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.
on 2013-02-05 22:05
$ = 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
on 2013-02-05 22:22
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.
on 2013-02-06 00:36
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 :)
on 2013-02-06 03:06
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". > 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
on 2013-02-06 03:45
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 2013-02-06 05:09
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. > 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 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
on 2013-02-06 05:20
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 2013-02-06 12:40
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. 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 2013-02-07 00:51
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.
on 2013-02-07 01:56
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. :)
on 2013-02-07 14:48
On Thu, Feb 7, 2013 at 1:56 AM, Student Jr <lists@ruby-forum.com> 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
on 2013-04-12 05:50
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
on 2013-04-12 06:38
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 http://stackoverflow.com/questions/5046831/why-use...
on 2013-04-12 10:37
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.
on 2013-04-12 13:42
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. > 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
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.