[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

What should this print?

Bouquet

3/2/2008 5:05:00 AM

Hi,

I was expecting the code below to print 1, 1,
but I get 1, nil.

old = nil
[1,1].each do |n|
if n != old
x = 1
old = n
end
p x
end

Thanks.
8 Answers

Ken Bloom

3/2/2008 6:02:00 AM

0

On Sun, 02 Mar 2008 05:04:47 +0000, Bouquet wrote:

> Hi,
>
> I was expecting the code below to print 1, 1, but I get 1, nil.
>
> old = nil
> [1,1].each do |n|
> if n != old
> x = 1
> old = n
> end
> p x
> end

After the first iteration, old is now 1. In the second iteration, n=1, so
1==1 and the code in if statement doesn't execute. Since x wasn't defined
outside of the block, it's created a new (or not) in each iteration, and
here it wasn't created, so its value when read (p x) is nil.

--Ken

--
Ken (Chanoch) Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu...

Mark Woodward

3/2/2008 6:42:00 AM

0

Hi Bouquet,

On Sun, 02 Mar 2008 05:04:47 GMT
Bouquet <news@soma.bpa.nu> wrote:

> Hi,
>
> I was expecting the code below to print 1, 1,
> but I get 1, nil.
>
> old = nil
> [1,1].each do |n|
> if n != old
> x = 1
> old = n
> end
> p x
> end
>
> Thanks.

1. old = nil
2. [1,1].each do |n|
3. if n != old
4. x = 1
5. old = n
6. end
7. p x
8. end


old was declared *outside* the each block at (1), so its remembered in,
as well as after the each block.

old = nil
[1,1].each do |n|
if n != old
x = 1
old = n
end
p x
end
puts "old outside the block: #{old}"


x declared *inside* the each block at (4), *only* when the if condition
is true! The first iteration (the first 1 in [1,1] at (2)), n doesn't
equal old (n=1, old=nil) so the if condition is true. So x is initiated
to 1, old becomes 1.
p x #=> prints 1
Now, (and this is a newbies understanding), at the end of this first
iteration at (8) x is forgotten. ie not available during the second
iteration.

If we start the second iteration, n=1 (the second 1 in [1,1] at (2)
and old (which *is* still available because it was declared outside the
each block) = 1. So if n=1 and old=1, we would never enter the if
statement at (3) and x would not be initiated. Hence p as nil.


Try this:

old = nil
[1,1].each do |n|
if n != old
x = 1
old = n
else
x = "what am I?"
end
p x
end


and this:


old = nil
x = nil
[1,1].each do |n|
if n != old
x = 1
old = n
end
p x
end


cheers,


--
Mark



Bouquet

3/2/2008 7:17:00 AM

0

Mark Woodward wrote:

> x declared *inside* the each block at (4), *only* when the if condition
> is true! The first iteration (the first 1 in [1,1] at (2)), n doesn't
> equal old (n=1, old=nil) so the if condition is true. So x is initiated
> to 1, old becomes 1.
> p x #=> prints 1
> Now, (and this is a newbies understanding), at the end of this first
> iteration at (8) x is forgotten. ie not available during the second
> iteration.
>
> If we start the second iteration, n=1 (the second 1 in [1,1] at (2)
> and old (which *is* still available because it was declared outside the
> each block) = 1. So if n=1 and old=1, we would never enter the if
> statement at (3) and x would not be initiated. Hence p as nil.

Thanks Mark for the explanation. I didn't realise that local
variables were reset every loop iteration; and not to undefined,
but to nil.


> old = nil
> x = nil
> [1,1].each do |n|
> if n != old
> x = 1
> old = n
> end
> p x
> end

Yes, this version does what I want.

Thanks again.

Bouquet

3/2/2008 10:46:00 PM

0

Ken Bloom wrote:

> After the first iteration, old is now 1. In the second iteration, n=1, so
> 1==1 and the code in if statement doesn't execute. Since x wasn't defined
> outside of the block, it's created a new (or not) in each iteration, and
> here it wasn't created, so its value when read (p x) is nil.

Thanks Ken.

It's different to not being created on that iteration, because I'd
then get "undefined local variable or method `x'", and the bug would
have flagged itself.

Bouquet

3/3/2008 1:28:00 AM

0

What about:

old = nil
for n in [1,1]
if n != old
x = 1
old = n
end
p x
end

Boson

4/10/2008 2:10:00 PM

0

With more context:

It's interesting that these two product different output:

old = nil
[1,1].each do |n|
if n != old
x = 1
old = n
end
p x
end

old = nil
for n in [1,1]
if n != old
x = 1
old = n
end
p x
end

Gregory Seidman

4/10/2008 2:28:00 PM

0

On Thu, Apr 10, 2008 at 11:15:04PM +0900, Boson wrote:
> With more context:
>
> It's interesting that these two product different output:
>
> old = nil
> [1,1].each do |n|
> if n != old
> x = 1
> old = n
> end
> p x
> end
>
> old = nil
> for n in [1,1]
> if n != old
> x = 1
> old = n
> end
> p x
> end

It's not especially interesting. The block passed to each has a local
variable, x, which is nil in the second iteration because it has never been
set. The for loop does not create a new scope, thus the x variable retains
the value it was set to in the previous iteration, i.e. 1.

Amusingly, if you run the two in the same Ruby instance in the opposite
order (the for loop first), you'd see identical output because in that case
x would have been declared in the outer scope and the block would be using
that x by closure.

--Greg


Boson

4/10/2008 3:24:00 PM

0

Gregory Seidman wrote:

> It's not especially interesting. The block passed to each has a local
> variable, x, which is nil in the second iteration because it has never been
> set. The for loop does not create a new scope, thus the x variable retains
> the value it was set to in the previous iteration, i.e. 1.

Thanks Greg, I'll read up on the creation of scope.

I'd assumed that "for" was just syntactic sugar for "each".