Scope issue of variable in iterator

mkhan@mkhan:~$ irb
irb(main):001:0> batman = 'robin'
=> "robin"
irb(main):002:0> [ 'cat', 'dog', 'horse', 'chicken' ].each { |batman|
puts batman }
cat
dog
horse
chicken
=> ["cat", "dog", "horse", "chicken"]
irb(main):003:0> puts "Now you might think this would say 'robin', but
it says: #{batman}"
Now you might think this would say 'robin', but it says: chicken
=> nil
irb(main):004:0>

···

--
Mohammad Khan | Software Engineer
Lextranet | 107 Union Wharf | Boston, MA 02109
http://www.lextranet.com
(617) 227-4469 Extension 218

Smart Tools. Smart Team. Smart Choice.

THE INFORMATION IN THIS MESSAGE IS INTENDED ONLY FOR THE PERSONAL AND
CONFIDENTIAL USE OF THE DESIGNATED RECIPIENTS NAMED ABOVE AND MAY
CONTAIN LEGALLY PRIVILEGED INFORMATION. If the reader of this message
is not the intended recipient or an agent responsible for delivering
it to the intended recipient, you are hereby notified that you have
received this document in error, and that any review, dissemination,
distribution or copying of this message is strictly prohibited. If
you have received this communication in error, please notify us
immediately by telephone at 617-227-4469 Ext. 200. Thank you.

It's true that blocks introduce a new scope.
However, if they use variables that are in scope outside the block,
they don't shadow those variables, they use them.

···

On 3/22/06, Mohammad Khan <mkhan@lextranet.com> wrote:

mkhan@mkhan:~$ irb
irb(main):001:0> batman = 'robin'
=> "robin"
irb(main):002:0> [ 'cat', 'dog', 'horse', 'chicken' ].each { |batman|
puts batman }
cat
dog
horse
chicken
=> ["cat", "dog", "horse", "chicken"]
irb(main):003:0> puts "Now you might think this would say 'robin', but
it says: #{batman}"
Now you might think this would say 'robin', but it says: chicken
=> nil

--
R. Mark Volkmann
Object Computing, Inc.

.... like in other programming languages as well.

    robert

···

Mark Volkmann <r.mark.volkmann@gmail.com> wrote:

On 3/22/06, Mohammad Khan <mkhan@lextranet.com> wrote:

mkhan@mkhan:~$ irb
irb(main):001:0> batman = 'robin'
=> "robin"
irb(main):002:0> [ 'cat', 'dog', 'horse', 'chicken' ].each { |batman|
puts batman }
cat
dog
horse
chicken
=> ["cat", "dog", "horse", "chicken"]
irb(main):003:0> puts "Now you might think this would say 'robin',
but it says: #{batman}"
Now you might think this would say 'robin', but it says: chicken
=> nil

It's true that blocks introduce a new scope.
However, if they use variables that are in scope outside the block,
they don't shadow those variables, they use them.

It's true that blocks introduce a new scope. However, if they use variables that are in scope outside the block, they don't shadow those variables, they use them.

about this block posted by Mohammad Khan

batman = 'robin'
[ 'cat', 'dog', 'horse', 'chicken' ].each { |batman| puts batman }
puts "Now you might think this would say 'robin', but it says: #{batman}"

where the last line outputs:

Now you might think this would say 'robin', but it says: chicken

With no variable declarations in Ruby, there's no way to control the scope, so the "first occurrence dictates scope" rule applies to Mohammad's example. I think that this is counter intuitive. I think that the pipe operators should be treated analogously to the way that C++ treats declarations that occur within an expression; viz., they are scoped to the end of the block dependent upon the expression.

Specifically, in C++ you have this:

int i = 5;
for (int i = 0; i < 100; i++) ...
printf("i=%u\n", i);

vs

int i = 5;
for (i = 0; i < 100; i++) ...
printf("i=%u\n", i);

I contend that the pipe operators are most intuitively understood as being an example of the first type of operation and not the second. It's safer, in any case, not to use duplicate variable names. Perhaps I'm too comfortable with this sort of thing because of the deeply entrenched habits accumulated from a background primarily in C, C++, and (later) Java. In perl, this would require the use of a local scope, which I've always hated.

In any case, before I ran the script that Mohammad has posted here, I fully expected such a piece of code to behave like the first instance and not like the second. This would have caused a bug that would have been nearly impossible for me to find.

···

On 3/22/06, Mark Volkmann <mkhan@lextranet.com> wrote:

-------------------------------------------------------
   David King Landrith
    (w) 617.227.4469x213
    (h) 617.696.7133

   One useless man is a disgrace, two
   are called a law firm, and three or more
   become a congress -- John Adams
-------------------------------------------------------
public key available upon request

When we are enjoying the freedom of using variable without
declearation, we are also loosing control over scope.

Mohammad

                       ^^^^^^^^^^^^^^^^^^^^^^^^^
                       gmail bug !!! ..

:

···

On 3/22/06, David King Landrith <dlandrith@mac.com> wrote:

On 3/22/06, Mark Volkmann <mkhan@lextranet.com> wrote

> It's true that blocks introduce a new scope. However, if they use
> variables that are in scope outside the block, they don't shadow
> those variables, they use them.

about this block posted by Mohammad Khan

> batman = 'robin'
> [ 'cat', 'dog', 'horse', 'chicken' ].each { |batman| puts batman }
> puts "Now you might think this would say 'robin', but it says: #
> {batman}"

where the last line outputs:

> Now you might think this would say 'robin', but it says: chicken

With no variable declarations in Ruby, there's no way to control the
scope, so the "first occurrence dictates scope" rule applies to
Mohammad's example. I think that this is counter intuitive. I think
that the pipe operators should be treated analogously to the way that
C++ treats declarations that occur within an expression; viz., they
are scoped to the end of the block dependent upon the expression.

Specifically, in C++ you have this:

int i = 5;
for (int i = 0; i < 100; i++) ...
printf("i=%u\n", i);

vs

int i = 5;
for (i = 0; i < 100; i++) ...
printf("i=%u\n", i);

I contend that the pipe operators are most intuitively understood as
being an example of the first type of operation and not the second.
It's safer, in any case, not to use duplicate variable names. Perhaps
I'm too comfortable with this sort of thing because of the deeply
entrenched habits accumulated from a background primarily in C, C++,
and (later) Java. In perl, this would require the use of a local
scope, which I've always hated.

In any case, before I ran the script that Mohammad has posted here, I
fully expected such a piece of code to behave like the first instance
and not like the second. This would have caused a bug that would have
been nearly impossible for me to find.

-------------------------------------------------------
   David King Landrith
    (w) 617.227.4469x213
    (h) 617.696.7133

   One useless man is a disgrace, two
   are called a law firm, and three or more
   become a congress -- John Adams
-------------------------------------------------------
public key available upon request

Mohammad Khan wrote:

When we are enjoying the freedom of using variable without
declearation, we are also loosing control over scope.

What exactly are you trying to convey? I don't see how the absence of variable declarations makes a difference with regard to scoping. By deciding where to use a variable I have exact the same control as in other languages.

Kind regards

  robert

Let me correct myself,
Actually we are not loosing control, its sort of inconvenience.

When I am writing
array.each do | blah | end

It would be really convenient if blah is scopped only in this iterator
block, regardless of blah decleared before or not.

Mohammad

···

On 3/24/06, Robert Klemme <bob.news@gmx.net> wrote:

Mohammad Khan wrote:
> When we are enjoying the freedom of using variable without
> declearation, we are also loosing control over scope.

What exactly are you trying to convey? I don't see how the absence of
variable declarations makes a difference with regard to scoping. By
deciding where to use a variable I have exact the same control as in
other languages.

Kind regards

        robert

Hi --

···

On Sat, 25 Mar 2006, Mohammad Khan wrote:

Let me correct myself,
Actually we are not loosing control, its sort of inconvenience.

When I am writing
array.each do | blah | end

It would be really convenient if blah is scopped only in this iterator
block, regardless of blah decleared before or not.

This has been discussed endlessly over the years on this list and
elsewhere. See archives, and also various indications from Matz about
what's planned for 2.0.

David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! Ruby for Rails

Mohammad Khan wrote:

Let me correct myself,
Actually we are not loosing control, its sort of inconvenience.

When I am writing
array.each do | blah | end

It would be really convenient if blah is scopped only in this iterator
block, regardless of blah decleared before or not.

You wouldn't be able to do things like this:

sum = 0
enum.each {|item| sum += item}

(I know there is inject for these cases but if you need to have more state variables it gets inconvenient at times.)

Regards

  robert

Not really; item being block-scoped wouldn't preclude access to other local
variables. What you wouldn't be able to do is:

def set_get
  a = nil
  [lambda{|a|}, lambda{a}]
end
set, get = set_get
set[1]
get # => 1

forcing you to go this way:
  [lambda{|b| a = b}, lambda{a}]

···

On Mon, Mar 27, 2006 at 04:23:54PM +0900, Robert Klemme wrote:

Mohammad Khan wrote:
>When I am writing
>array.each do | blah | end
>
>It would be really convenient if blah is scopped only in this iterator
>block, regardless of blah decleared before or not.

You wouldn't be able to do things like this:

sum = 0
enum.each {|item| sum += item}

--
Mauricio Fernandez - http://eigenclass.org - singular Ruby

Mauricio Fernandez wrote:

Mohammad Khan wrote:

When I am writing
array.each do | blah | end

It would be really convenient if blah is scopped only in this iterator
block, regardless of blah decleared before or not.

You wouldn't be able to do things like this:

sum = 0
enum.each {|item| sum += item}

Not really; item being block-scoped wouldn't preclude access to other local
variables.

Right. Apparently I wasn't fully awake when I wrote that.

> What you wouldn't be able to do is:

def set_get
  a = nil
  [lambda{|a|}, lambda{a}]
end
set, get = set_get
set[1]
get # => 1

forcing you to go this way:
  [lambda{|b| a = b}, lambda{a}]

Seems like a rare thing to do. This is another thing you cannot do with the proposed change:

last = nil
enum.each {|last|}
puts "last was #{last}"

Although you can of course with #inject.

Kind regards

  robert

···

On Mon, Mar 27, 2006 at 04:23:54PM +0900, Robert Klemme wrote:

Seems like a rare thing to do. This is another thing you cannot do with
the proposed change:

last = nil
enum.each {|last|}
puts "last was #{last}"

last = nil
last = enum.last

I think, out of 100 uses of iterator, less then one would be the
example you shown above.

Key point of this thread was, what is more convenient,
To keep variable in iterator scoped in its block, even though the same
name already used as vairable name or not.

Mohammad

Regardless of where it's used, ruby does not have dynamic scoping (explicitly or implicitly)

···

On 2006-03-27 07:46:15 -0800, "Mohammad Khan" <beeplove@gmail.com> said:

Seems like a rare thing to do. This is another thing you cannot do with
the proposed change:

last = nil
enum.each {|last|}
puts "last was #{last}"

last = nil
last = enum.last

I think, out of 100 uses of iterator, less then one would be the
example you shown above.

Key point of this thread was, what is more convenient,
To keep variable in iterator scoped in its block, even though the same
name already used as vairable name or not.