[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: Pickaxe question: "... on the way to true Ruby mastery."

Andreas S

1/3/2007 5:29:00 AM

My guess is it is necessary to keep the value in the array in case the real
value is nil. Without it in an array, @__#{id.to_i}__ will evaluate to nil,
and the || operator will execute the next term, the function call. You don't
want to call the function again, your desired value is already in the
instance variable and it is nil.

(@__#{id.to_i}__ ||= [__#{id.to_i}__(*args, &block)])[0]

-andre

>From: jeffz_2002@yahoo.com
>Reply-To: ruby-talk@ruby-lang.org
>To: ruby-talk@ruby-lang.org (ruby-talk ML)
>Subject: Pickaxe question: "... on the way to true Ruby mastery."
>Date: Wed, 3 Jan 2007 13:55:08 +0900
>
>Pickaxe has this code on page 374:
>
>def once(*ids) # :nodoc:
> for id in ids
> module_eval <<-"end;"
> alias_method :__#{id.to_i}__, :#{id.to_s}
> private :__#{id.to_i}__
> def #{id.to_s}(*args, &block)
> (@__#{id.to_i}__ ||= [__#{id.to_i}__(*args, &block)])[0]
> end
>end;
>end
>end
>
>followed by "Understand this code, and you'll be well on the way to
>true Ruby mastery." I don't, so I'm not, but would like to, and then I
>will (according to the book) - with some help.
>
>I'm good up until the line (@__#{id.to_i}__ ||= [__#{id.to_i}__(*args,
>&block)])[0]
>
>Say the id.to_i was 42 ... then this reads: (@__42__ ||= [__42__(*args,
>&block)])[ 0 ]
>
>or: (@__42__ ||= [ return value from __42__ method call ] )[ 0 ]
>
>
>Question: Why can't we just write
>
>(@__42__ ||= return value from __42__ method call)
>
>Why is the [0] necessary at all?
>
>Thanks, (ps - a link to an in-depth explanation would be sufficient!)
>
>Jeff
>
>

_________________________________________________________________
Get live scores and news about your team: Add the Live.com Football Page
www.live.com/?addtemplate=football&icid=T001MSN30A0701


5 Answers

jeffz_2002

1/3/2007 5:56:00 AM

0

Hey Andre, I believe the line reads slightly differently than you've
interpreted ... some more info (note: I still don't have the answer):

||= is actually a ruby idiom to initialize a variable if it's nil. In
other words, "a ||= 6" actually means "a = 6 if a.nil?" or "a = 6
unless a". (sorry if I'm lecturing) In other words, if @foo really
*is* a value, and it really *is* nil, I think the function call is
going to be made no matter what ... but again, this is a bit over my
head at present.

So, converting __#{id.to_i}__ to something more readable, like "foo",
this: (@foo ||= [foo(*a, &b)] )[ 0 ]

should be the same as the more verbose:

if @foo
return @foo[ 0 ] # Still not sure why the [0] is required!
else
return foo( *a, &b ) # the 0th index of the single array
end

jz

dblack

1/3/2007 9:21:00 AM

0

jeffz_2002

1/3/2007 6:04:00 PM

0

Thanks David and Andre, I finally get it, and Andre, you're right about
the nil/false idea in your response to my reponse.

For anyone else following this thread, the idea is:

- The first time the method is called, @foo doesn't exist.

- @foo doesn't exist, so it's assigned a single-element array
containing the value returned by the call to the private aliased
original method. This value can be anything, including an array,
false, nil, whatever.

- The 0th array element, which is just the return value of the function
call, is returned.

- The next time the method is called, @foo still exists, and is still a
single-element array. We again return the 0th element, which is the
answer.

The [0] is used because the result is stored in an array ... this gets
around the original method returning nil or false, which would end up
in a second call to the function, had we just naively used @foo ||=
foo( *args, &block )..

Thanks again. It's pretty obvious, actually ... sigh.

Funny, I still don't feel well on my way to mastery. I actually feel
dumber, in a way.

jz

dblack

1/3/2007 7:10:00 PM

0

Kenosis

1/3/2007 10:52:00 PM

0


jeffz_2002@yahoo.com wrote:
> Thanks David and Andre, I finally get it, and Andre, you're right about
> the nil/false idea in your response to my reponse.
>
> For anyone else following this thread, the idea is:
>
> - The first time the method is called, @foo doesn't exist.
>
> - @foo doesn't exist, so it's assigned a single-element array
> containing the value returned by the call to the private aliased
> original method. This value can be anything, including an array,
> false, nil, whatever.
>
> - The 0th array element, which is just the return value of the function
> call, is returned.
>
> - The next time the method is called, @foo still exists, and is still a
> single-element array. We again return the 0th element, which is the
> answer.
>
> The [0] is used because the result is stored in an array ... this gets
> around the original method returning nil or false, which would end up
> in a second call to the function, had we just naively used @foo ||=
> foo( *args, &block )..
>
> Thanks again. It's pretty obvious, actually ... sigh.
>
> Funny, I still don't feel well on my way to mastery. I actually feel
> dumber, in a way.
>
> jz

Welcome to the wonderful world of meta-programming in Ruby! And don't
feel dumb. As the saying goes: the more you know, the more you know
that you don't know. Ask any true master of anything and that'll be
the answer they give you; if they're a >true< master.

Ken

PS. Check these out to continue your mastery...

http://www.erikveen.dds.nl/monitorfunctions/...
http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/22b97167fe614efc/2627d192d2bf56d5?hl=en#2627d1...