Creating independent lambdas in loops

Completely true. If a variable of that name is already defined it is
used (and no local variables are created).

cheers

Simon

···

-----Original Message-----
From: Michael Roth [mailto:mroth@nessie.de]
Sent: Wednesday, September 28, 2005 3:12 PM
To: ruby-talk ML
Subject: Re: creating independent lambdas in loops

Michael Roth wrote:

> Already tried. Doesn't work... :-\

Argh, stop. Looks like it works. But only if 'multi' doesn't appears
somewhere before the each-loop.

--- "Kroeger Simon (ext)" <simon.kroeger.ext@siemens.com>
wrote:

···

> -----Original Message-----
> From: Michael Roth [mailto:mroth@nessie.de]
> Sent: Wednesday, September 28, 2005 3:12 PM
> To: ruby-talk ML
> Subject: Re: creating independent lambdas in loops
>
> Michael Roth wrote:
>
> > Already tried. Doesn't work... :-\
>
> Argh, stop. Looks like it works. But only if 'multi'
doesn't appears
> somewhere before the each-loop.

Completely true. If a variable of that name is already
defined it is
used (and no local variables are created).

Does anyone else find this "feature" useful?

Is there any way to create a local variable to a block where
that variable name is already used? Most other languages have
this ability but it looks like ruby doesn't.

__________________________________
Yahoo! Mail - PC Magazine Editors' Choice 2005

Does anyone else find this "feature" useful?

Read the archive : you have at least 10000 messages on this subject :slight_smile:

Guy Decoux

it's everywhere in ruby - it's called the 'block' :wink:

   harp:~ > cat a.rb
   def scope *vars; yield *vars; end

   x, y = 0b101010, 0b0

   p y

   scope(x){|y| p y}

   harp:~ > ruby a.rb
   0
   42

cheers.

-a

···

On Wed, 28 Sep 2005, Eric Mahurin wrote:

--- "Kroeger Simon (ext)" <simon.kroeger.ext@siemens.com>
wrote:

-----Original Message-----
From: Michael Roth [mailto:mroth@nessie.de]
Sent: Wednesday, September 28, 2005 3:12 PM
To: ruby-talk ML
Subject: Re: creating independent lambdas in loops

Michael Roth wrote:

Already tried. Doesn't work... :-\

Argh, stop. Looks like it works. But only if 'multi'

doesn't appears

somewhere before the each-loop.

Completely true. If a variable of that name is already
defined it is
used (and no local variables are created).

Does anyone else find this "feature" useful?

Is there any way to create a local variable to a block where
that variable name is already used? Most other languages have
this ability but it looks like ruby doesn't.

--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
Your life dwells amoung the causes of death
Like a lamp standing in a strong breeze. --Nagarjuna

===============================================================================

All the time! I would say that at least half the programs I write use this feature of the blocks-as-closures.

···

On Sep 28, 2005, at 7:47 AM, Eric Mahurin wrote:

Completely true. If a variable of that name is already
defined it is
used (and no local variables are created).

Does anyone else find this "feature" useful?

Add another "p y" and you'll see y wasn't localized in the
block. The block just caused y to be assigned to x.

What I'm asking is this:

f = nil
y = 1
localize { |y| # localize y and call this block
  y = 2
  f = lambda { y }
}
p y # => 1
p f.call # => 2
y = 3
p y # => 3
p f.call # => 2

Anyway to get this functionality?

If block arguments were always made local (regardless of
whether that variable was assigned yet or not), we could have
done this to be the equivalent of the above localize:

lambda { |y|
  y = 2
  f = lambda {y}
}.call(nil)

···

--- "Ara.T.Howard" <Ara.T.Howard@noaa.gov> wrote:

On Wed, 28 Sep 2005, Eric Mahurin wrote:

> --- "Kroeger Simon (ext)" <simon.kroeger.ext@siemens.com>
> wrote:
>>> -----Original Message-----
>>> From: Michael Roth [mailto:mroth@nessie.de]
>>> Sent: Wednesday, September 28, 2005 3:12 PM
>>> To: ruby-talk ML
>>> Subject: Re: creating independent lambdas in loops
>>>
>>> Michael Roth wrote:
>>>
>>>> Already tried. Doesn't work... :-\
>>>
>>> Argh, stop. Looks like it works. But only if 'multi'
>> doesn't appears
>>> somewhere before the each-loop.
>>
>> Completely true. If a variable of that name is already
>> defined it is
>> used (and no local variables are created).
>
> Does anyone else find this "feature" useful?
>
> Is there any way to create a local variable to a block
where
> that variable name is already used? Most other languages
have
> this ability but it looks like ruby doesn't.

it's everywhere in ruby - it's called the 'block' :wink:

   harp:~ > cat a.rb
   def scope *vars; yield *vars; end

   x, y = 0b101010, 0b0

   p y

   scope(x){|y| p y}

   harp:~ > ruby a.rb
   0
   42

______________________________________________________
Yahoo! for Good
Donate to the Hurricane Katrina relief effort.
http://store.yahoo.com/redcross-donate3/

I'm talking about specifically block arguments (the only
variables in a block that can be local to the block). i.e.
this:

x = 0
[1,2,3,4].each {|x|}
x # => 4 # block argument changed x

compared to:

[1,2,3,4].each {|x|}
x # undefined local variable or method 'x'

I find this dual behavior annoying - that a local variable is
created only if the variable doesn't exist in the current scope
already. I would have rather it always be created so that if
you did want an argument to be assigned to a variable outside
the block, you'd have to do it explicitly:

x = 0
[1,2,3,4].each {|y| x = y }
x # => 4

···

--- Gavin Kistner <gavin@refinery.com> wrote:

On Sep 28, 2005, at 7:47 AM, Eric Mahurin wrote:
>> Completely true. If a variable of that name is already
>> defined it is
>> used (and no local variables are created).
>
> Does anyone else find this "feature" useful?

All the time! I would say that at least half the programs I
write use
this feature of the blocks-as-closures.

__________________________________
Yahoo! Mail - PC Magazine Editors' Choice 2005

Add another "p y" and you'll see y wasn't localized in the block. The block
just caused y to be assigned to x.

you are right - i'd forgotten about that...

What I'm asking is this:

f =3D nil
y =3D 1
localize { |y| # localize y and call this block
y =3D 2
f =3D lambda { y }
}
p y # =3D> 1
p f.call # =3D> 2
y =3D 3
p y # =3D> 3
p f.call # =3D> 2

Anyway to get this functionality?

If block arguments were always made local (regardless of
whether that variable was assigned yet or not), we could have
done this to be the equivalent of the above localize:

lambda { |y|
y =3D 2
f =3D lambda {y}
}.call(nil)

i think you would have to do the black magic for this to work - i've asked for
it myself before...

btw. you mailer munges your posts pretty bad - i get them as they appear
above.

cheers.

-a

···

On Wed, 28 Sep 2005, Eric Mahurin wrote:
--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
Your life dwells amoung the causes of death
Like a lamp standing in a strong breeze. --Nagarjuna

===============================================================================

Ah, right. Sorry, I was responding only to the bit I quoted, not properly following the thread of the conversation.

No, I don't think I have ever personally used that and wanted it, and it has bitten me before (at least twice). It's like this sort of mistake in JS:

for (var i=0, len=myArray.length; i<len; ++i ){
     for ( var j=0, len2=myArray.length; j<len2; ++j ){
         #lots
         #of
         #code
         for ( var i=0, len=myArray.length; i<len; ++i ){
             #OOPS
         }
       }
}

In the same way that I hate having to come up with unique names for nested iterators variables, and be sure I'm using the right one, and never copy/paste code with the wrong one into place...well, I similarly dislike being unable to re-use the same local variable name for a block when doing iterations-in-iterations.

I, for one, would be fine with block arguments always being block-local, even if it means they mask access to local variables outside the closure.

···

On Sep 28, 2005, at 9:29 AM, Eric Mahurin wrote:

--- Gavin Kistner <gavin@refinery.com> wrote:

On Sep 28, 2005, at 7:47 AM, Eric Mahurin wrote:

Completely true. If a variable of that name is already
defined it is used (and no local variables are created).

Does anyone else find this "feature" useful?

All the time! I would say that at least half the programs I
write use this feature of the blocks-as-closures.

I'm talking about specifically block arguments (the only
variables in a block that can be local to the block).

Sorry, the above statement is wrong. After doing some irb
experiments I was thinking that only block arguments made local
variables. My mistake was that I assumed that the code in a
for/in statement was just like a block. Even though it uses
#each, I guess the block it gives to each is a different beast:

[1,2,3,4].each do |x| y = x end
p x # undefined local variable or method
p y # undefined local variable or method

for x in [1,2,3,4]; y = x; end
p x # -> 4
p y # -> 4

[1,2,3,4].each do |x| y = x end
p x # -> 4 # for loop defined x before this each loop
p y # -> 4 # for loop defined y before this each loop

It still seems like there should be a way to controll variable
locality in blocks better. Making the variable local just
based on whether the variable already exists in the outer scope
doesn't cut it.

···

--- Eric Mahurin <eric_mahurin@yahoo.com> wrote:

I'm talking about specifically block arguments (the only
variables in a block that can be local to the block).

__________________________________
Yahoo! Mail - PC Magazine Editors' Choice 2005

Hi --

···

On Thu, 29 Sep 2005, Eric Mahurin wrote:

It still seems like there should be a way to controll variable
locality in blocks better. Making the variable local just
based on whether the variable already exists in the outer scope
doesn't cut it.

It's never bothered me to view block variable assignment as
assignment to existing variables, but I know I'm in a small minority
which, among other things, does not include Matz :slight_smile: You can expect
this to change in Ruby 2.0.

David

--
David A. Black
dblack@wobblini.net

Any idea what the planned change is going to be? New construct
like:

localize(:a,:b) {...}

Or maybe an incompatible change like making all block arguments
local no matter what.

It would be nice if all definite changes were put on rcrchive
and marked as accepted. And somehow put the potential changes
in there too. Or is there another place where this information
is held?

···

--- "David A. Black" <dblack@wobblini.net> wrote:

On Thu, 29 Sep 2005, Eric Mahurin wrote:

> It still seems like there should be a way to control
variable
> locality in blocks better. Making the variable local just
> based on whether the variable already exists in the outer
scope
> doesn't cut it.

It's never bothered me to view block variable assignment as
assignment to existing variables, but I know I'm in a small
minority
which, among other things, does not include Matz :slight_smile: You can
expect
this to change in Ruby 2.0.

__________________________________
Yahoo! Mail - PC Magazine Editors' Choice 2005

Hi --

It still seems like there should be a way to control

variable

locality in blocks better. Making the variable local just
based on whether the variable already exists in the outer

scope

doesn't cut it.

It's never bothered me to view block variable assignment as
assignment to existing variables, but I know I'm in a small
minority
which, among other things, does not include Matz :slight_smile: You can
expect
this to change in Ruby 2.0.

Any idea what the planned change is going to be? New construct
like:

localize(:a,:b) {...}

Hopefully nothing quite that obviously "added as an afterthought to
the language" :slight_smile:

Or maybe an incompatible change like making all block arguments
local no matter what.

See http://www.rubyist.net/~matz/slides/rc2003/mgp00010.html and the
slides following that one. I think the idea would be:

   a = 1
   method_call {|a| a = 2; b = 3 }
   puts a # 1
   puts b # 3

It would be nice if all definite changes were put on rcrchive
and marked as accepted. And somehow put the potential changes
in there too. Or is there another place where this information
is held?

That's really not what RCRchive is for; it's for the processing by
Matz of change requests from other people. I think discussion of
possible changes coming from Matz is spread around -- Matz's blog,
ruby-core, here, the TODO file, etc.

David

···

On Thu, 29 Sep 2005, Eric Mahurin wrote:

--- "David A. Black" <dblack@wobblini.net> wrote:

On Thu, 29 Sep 2005, Eric Mahurin wrote:

--
David A. Black
dblack@wobblini.net

oh gawd - that's horrible : variables exported from method scope to the global
(or enclosing perhaps?) one. eeks!

being able to create top level vars from inside methods would, at least,
introduce a massive garbage collection issue and, at most, introduce millions
of very hard to track down bugs.

im__h__o.

cheers.

-a

···

On Thu, 29 Sep 2005, David A. Black wrote:

See http://www.rubyist.net/~matz/slides/rc2003/mgp00010.html and the
slides following that one. I think the idea would be:

a = 1
method_call {|a| a = 2; b = 3 }
puts a # 1
puts b # 3

--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
Your life dwells amoung the causes of death
Like a lamp standing in a strong breeze. --Nagarjuna

===============================================================================

Yeah, I'm not fond of it either. I believe the goal is to make variable behavior more consistent, but I don't like the "leakage".

James Edward Gray II

···

On Sep 28, 2005, at 12:42 PM, Ara.T.Howard wrote:

On Thu, 29 Sep 2005, David A. Black wrote:

See http://www.rubyist.net/~matz/slides/rc2003/mgp00010.html and the
slides following that one. I think the idea would be:

a = 1
method_call {|a| a = 2; b = 3 }
puts a # 1
puts b # 3

oh gawd - that's horrible : variables exported from method scope to the global
(or enclosing perhaps?) one. eeks!

being able to create top level vars from inside methods would, at least,
introduce a massive garbage collection issue and, at most, introduce millions
of very hard to track down bugs.

im__h__o.

Blocks exist in the caller's scope, not the method's, so I don't really
see the problem here.

martin

···

Ara.T.Howard <Ara.T.Howard@noaa.gov> wrote:

On Thu, 29 Sep 2005, David A. Black wrote:
>
> a = 1
> method_call {|a| a = 2; b = 3 }
> puts a # 1
> puts b # 3

oh gawd - that's horrible : variables exported from method scope to the global
(or enclosing perhaps?) one. eeks!

I like it. The variable locality is independent of whether or
not the variable existed in the outside scope (it is dependent
on that now). Arguments would be local and other variables
would be in the context of what contains the block. Period.
With this you could easily create a localize method:

def localize(&block)
  yield(*Array.new(block.arity)) # arity can't be <0
end

Then this would localize x and y for you (initialize to nil):

localize { |x,y| ... }

···

--- Martin DeMello <martindemello@yahoo.com> wrote:

Ara.T.Howard <Ara.T.Howard@noaa.gov> wrote:
> On Thu, 29 Sep 2005, David A. Black wrote:
> >
> > a = 1
> > method_call {|a| a = 2; b = 3 }
> > puts a # 1
> > puts b # 3
>
> oh gawd - that's horrible : variables exported from method
scope to the global
> (or enclosing perhaps?) one. eeks!

Blocks exist in the caller's scope, not the method's, so I
don't really
see the problem here.

martin

__________________________________
Yahoo! Mail - PC Magazine Editors' Choice 2005

but it totally violates structured programming principles - methods pollute
the heap : data from methods (stack) is not freed when the method returnes.
eg:

   # method which sets up x on the heap

   method_call { x = 42 }

   # we cannot free x here - someone may want to print it below

   p x

   # we cannot free x here - someone may still want to print it below

   p x

   # when can we free it?

so all non-local variables would need to live on the heap forever. that'd
make it pretty easy to run out of memory in any sort of tight loop.

afaikt variables created like that could never be freed because there'd be no
way to know if someone would refer to them, at some point in the future, after
the method or not. it seems like the only safe way to deal with that sort of
thing is pushing/poping them to/from the stack so they are freed on method
exit. but maybe i'm missing something obvious here?

regards.

-a

···

On Thu, 29 Sep 2005, Eric Mahurin wrote:

--- Martin DeMello <martindemello@yahoo.com> wrote:

Ara.T.Howard <Ara.T.Howard@noaa.gov> wrote:

On Thu, 29 Sep 2005, David A. Black wrote:

a = 1
method_call {|a| a = 2; b = 3 }
puts a # 1
puts b # 3

oh gawd - that's horrible : variables exported from method

scope to the global

(or enclosing perhaps?) one. eeks!

Blocks exist in the caller's scope, not the method's, so I
don't really
see the problem here.

martin

I like it. The variable locality is independent of whether or
not the variable existed in the outside scope (it is dependent
on that now). Arguments would be local and other variables
would be in the context of what contains the block. Period.
With this you could easily create a localize method:

def localize(&block)
yield(*Array.new(block.arity)) # arity can't be <0
end

Then this would localize x and y for you (initialize to nil):

localize { |x,y| ... }

--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
Your life dwells amoung the causes of death
Like a lamp standing in a strong breeze. --Nagarjuna

===============================================================================

You should be able to free x as soon as the enclosing methods
completes, right?

How about this one:

def foo
  a = [1,2,3]
  lambda { x = 42 }
end

f = foo
f.call # => 42
eval("a",f.binding) # => [1,2,3]

When you start passing around blocks/lambdas, you prevent all
of the variables in surrounding scope from being GC'ed because
of the #binding link. All for the sake of an eval on the
binding. I think this is a larger issue than the one you are
discussing.

There are several ways you could treat variables within blocks:

- local if not in surrounding scope (now in 1.8)
- local with no relation to surrounding scope (2.0 args)
- local and intialized to same value in surrounding scope
- same scope as surrounding scope (2.0 other variables)

I think it is hard to pick from these. You can make an
argument that any of these are useful. It would be nice to be
able to control this more directly, but this may also reduce
readability.

···

--- "Ara.T.Howard" <Ara.T.Howard@noaa.gov> wrote:

On Thu, 29 Sep 2005, Eric Mahurin wrote:

> --- Martin DeMello <martindemello@yahoo.com> wrote:
>
>> Ara.T.Howard <Ara.T.Howard@noaa.gov> wrote:
>>> On Thu, 29 Sep 2005, David A. Black wrote:
>>>>
>>>> a = 1
>>>> method_call {|a| a = 2; b = 3 }
>>>> puts a # 1
>>>> puts b # 3
>>>
>>> oh gawd - that's horrible : variables exported from
method
>> scope to the global
>>> (or enclosing perhaps?) one. eeks!
>>
>> Blocks exist in the caller's scope, not the method's, so I
>> don't really
>> see the problem here.
>>
>> martin
>
> I like it. The variable locality is independent of whether
or
> not the variable existed in the outside scope (it is
dependent
> on that now). Arguments would be local and other variables
> would be in the context of what contains the block.
Period.
> With this you could easily create a localize method:
>
> def localize(&block)
> yield(*Array.new(block.arity)) # arity can't be <0
> end
>
> Then this would localize x and y for you (initialize to
nil):
>
> localize { |x,y| ... }

but it totally violates structured programming principles -
methods pollute
the heap : data from methods (stack) is not freed when the
method returnes.
eg:

   # method which sets up x on the heap

   method_call { x = 42 }

   # we cannot free x here - someone may want to print it
below

   p x

   # we cannot free x here - someone may still want to print
it below

   p x

   # when can we free it?

so all non-local variables would need to live on the heap
forever. that'd
make it pretty easy to run out of memory in any sort of tight
loop.

afaikt variables created like that could never be freed
because there'd be no
way to know if someone would refer to them, at some point in
the future, after
the method or not. it seems like the only safe way to deal
with that sort of
thing is pushing/poping them to/from the stack so they are
freed on method
exit. but maybe i'm missing something obvious here?

__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around

You should be able to free x as soon as the enclosing methods completes,
right?

what if there is no eclosing method - eg. you are at the top level and

   def method &block
     yield
   end

   method do
     f = open 'gigantic', 'r'
     memory_leak = f.read
   ensure
     f.close
   end

every single method available at the top level would leave it's block
variables in the top level forever! after a few method calls
'local_variables' would return a list 10,000 items long. they could never be
gc'd. it's true that lambda's keeps vars from being gc'd - but this approach
would prevent every named var of every top-level method called with a block
from being re-claimed. consider open as an example - how easy to leak a
buffer...

i also don't like how you are limited to making local what the designer of the
block allowed - eg. only a, b, and c are not leaked here

   def method &block
     yield 1,2,3
   end

   method{|a,b,c| p [a,b,c]; d = 42}

so there's no way for client code to keep something local... or am i missing
something?

How about this one:

def foo
a = [1,2,3]
lambda { x = 42 }
end

f = foo
f.call # => 42
eval("a",f.binding) # => [1,2,3]

well that's a different beast - you created the lambda explicitly. i'm
worried about implicit pervasives.

When you start passing around blocks/lambdas, you prevent all of the
variables in surrounding scope from being GC'ed because of the #binding
link. All for the sake of an eval on the binding. I think this is a larger
issue than the one you are discussing.

agreed.

There are several ways you could treat variables within blocks:

- local if not in surrounding scope (now in 1.8)
- local with no relation to surrounding scope (2.0 args)
- local and intialized to same value in surrounding scope
- same scope as surrounding scope (2.0 other variables)

I think it is hard to pick from these. You can make an argument that any of
these are useful. It would be nice to be able to control this more
directly, but this may also reduce readability.

if the aim is to unify lambda and methods then the move must be towards local
vars only no? perhaps with a more capable Binding or Scope object? it's
tough to say what matz it thinking - i'd like to hear before i say much
more.

i suppose we'd adapt to whatever came up - but it seems like a dangerous
change.

cheers.

-a

···

On Thu, 29 Sep 2005, Eric Mahurin wrote:
--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
Your life dwells amoung the causes of death
Like a lamp standing in a strong breeze. --Nagarjuna

===============================================================================