This looks like a pretty serious bug. It seems that lambda-
expressions are not properly localizing their formal arguments:
bash-3.2$ ruby --version
ruby 1.8.6 (2007-03-13 patchlevel 0) [i386-mswin32]
bash-3.2$ cat lambda-bug.rb
a = 0
f = lambda { |a| a }
puts “a = #{a}”
puts “f.call(1) => #{f.call(1)}”
puts “now a = #{a}”
bash-3.2$ ruby lambda-bug.rb
a = 0
f.call(1) => 1
now a = 1
On 9/8/07, kevin cline [email protected] wrote:
puts “f.call(1) => #{f.call(1)}”
puts “now a = #{a}”
bash-3.2$ ruby lambda-bug.rb
a = 0
f.call(1) => 1
now a = 1
This is the expected behavior of Ruby 1.8.
‘lambda’ and ‘proc’ are expected to diverge further in future versions.
On 9/8/07, kevin cline [email protected] wrote:
puts “f.call(1) => #{f.call(1)}”
puts “now a = #{a}”
bash-3.2$ ruby lambda-bug.rb
a = 0
f.call(1) => 1
now a = 1
Not a bug, it’s a “feature”. I don’t like it either.
foo = lambda { |$this_works_too| }
foo.call(2)
p $this_works_too
class SoDoesThis
attr_reader :foo
def setter
lambda { |@foo| }
end
end
bar = SoDoesThis.new
bar.setter[“this is sparta”]
p bar.foo
On Saturday 08 September 2007 08:15:06 pm kevin cline wrote:
puts “f.call(1) => #{f.call(1)}”
puts “now a = #{a}”
bash-3.2$ ruby lambda-bug.rb
a = 0
f.call(1) => 1
now a = 1
IIRC this is a ruby 1.8.x thing; it will be fixed in 1.9. Don’t depend
on
this behaviour / try to avoid repeating variable names :D.
Cheers,
In 1.9 it won’t be able to access local scope?
Hi –
On Sun, 9 Sep 2007, kevin cline wrote:
puts “f.call(1) => #{f.call(1)}”
puts “now a = #{a}”
bash-3.2$ ruby lambda-bug.rb
a = 0
f.call(1) => 1
now a = 1
Definitely not a bug. Block parameters use assignment semantics, with
regard to the scope in which the block appears. In your example,
you’re assigning 1 to a. If you create a local variable inside the
block, however, it only exists for the duration of the block.
As far as remember, Guy Decoux and I are the only two people who think
that this makes perfect sense, once you learn it, and should not be
changed ![:slight_smile: :slight_smile:](/images/emoji/twitter/slight_smile.png?v=6)
David
On 9/9/07, Bernardo Monteiro R. [email protected] wrote:
In 1.9 it won’t be able to access local scope?
No, just not the arguments. The following will still work:
a = 1
foo = lambda { a = 99 }
foo.call
p a # prints 99
This looks like a pretty serious bug.
I guess you didn’t read p. 51 of “Programming Ruby (2nd Ed)”. You can
read the first edition online. See the section Implementing Iterators
here:
http://www.rubycentral.com/pickaxe/tut_containers.html
As far as remember, Guy Decoux and I are the only two people who think
that this makes perfect sense, once you learn it, and should not be
changed ![:slight_smile: :slight_smile:](https://www.ruby-forum.com/images/emoji/apple/slight_smile.png?v=12)
The behavior in question seems consistent with the way closures work in
Ruby:
def func(x)
y = 10
lambda {puts x+y; y += 1}
end
p = func(5)
p.call
p.call
p.call
–output:–
15
16
17
Is there something inconsistent with the way a block defined outside of
any functions behaves versus a closure?
7stud – wrote:
Is there something inconsistent with the way a block defined outside of
any functions behaves versus a closure?
Whoops. Methods, methods…
7stud – wrote:
The behavior in question seems consistent with the way closures work in
Ruby:
def func(x)
y = 10
lambda {puts x+y; y += 1}
end
p = func(5)
p.call
p.call
p.call
–output:–
15
16
17
Is there something inconsistent with the way a block defined outside of
any functions behaves versus a closure?
I guess this would be a more complete example:
$z = 100
def func(x)
y = 10
lambda {
puts x+y+$z
x+=1
y += 1
$z+=100
}
end
p = func(5)
p.call
p.call
p.call
–output:–
115
217
319
On 9/9/07, [email protected] [email protected] wrote:
As far as remember, Guy Decoux and I are the only two people who think
that this makes perfect sense, once you learn it, and should not be
changed ![:slight_smile: :slight_smile:](https://www.ruby-forum.com/images/emoji/apple/slight_smile.png?v=12)
I think it shouldn’t be changed too…
On 9/9/07, Logan C. [email protected] wrote:
On 9/9/07, Bernardo Monteiro R. [email protected] wrote:
On 9/9/07, [email protected] [email protected] wrote:
As far as remember, Guy Decoux and I are the only two people who think
that this makes perfect sense, once you learn it, and should not be
changed ![:slight_smile: :slight_smile:](https://www.ruby-forum.com/images/emoji/apple/slight_smile.png?v=12)
This one is my favorite.
P.S. Don’t use this in ‘real’ code or I will be forced to hunt you
like a wild animal through the streets of your city. =(
hydra>cat eye_of_terror.rb
h = {}
f = lambda {|h[:x]| }
f[7]
p h
hydra>ruby eye_of_terror.rb
{:x=>7}
Hi –
On Mon, 10 Sep 2007, Wilson B. wrote:
P.S. Don’t use this in ‘real’ code or I will be forced to hunt you
like a wild animal through the streets of your city. =(
hydra>cat eye_of_terror.rb
h = {}
f = lambda {|h[:x]| }
f[7]
p h
hydra>ruby eye_of_terror.rb
{:x=>7}
Hey, nothing wrong with that – it’s just like
h[:x] = 7
but in slightly different form. But like I said, I’m one of the few
who think that there’s nothing wrong with assignment semantics for
block parameters ![:slight_smile: :slight_smile:](/images/emoji/twitter/slight_smile.png?v=6)
David
On 9/9/07, Bernardo Monteiro R. [email protected] wrote:
On 9/9/07, [email protected] [email protected] wrote:
As far as remember, Guy Decoux and I are the only two people who think
that this makes perfect sense, once you learn it, and should not be
changed ![:slight_smile: :slight_smile:](https://www.ruby-forum.com/images/emoji/apple/slight_smile.png?v=12)
I think it shouldn’t be changed too…
I just think it has icky semantics.
a.rb:
fib = lambda do |a|
if a == 1 or a == 0
1
else
fib[a - 1] + fib[a - 2]
end
end
p fib.call(10)
C:\Documents and Settings\Logan>ruby a.rb
89
vs.
b.rb:
a = nil
fib = lambda do |a|
if a == 1 or a == 0
1
else
fib[a - 1] + fib[a - 2]
end
end
p fib.call(10)
C:\Documents and Settings\Logan>ruby b.rb
b.rb:6: stack level too deep (SystemStackError)
from b.rb:6
from b.rb:6
from b.rb:6
from b.rb:6
from b.rb:6
from b.rb:6
from b.rb:6
from b.rb:6
… 633 levels…
from b.rb:6
from b.rb:6
from b.rb:6
from b.rb:10
Am I the only one who makes use of recursive lambdas?
If we keep
assignment semantics for block arguments, I think we should disallow
recursive blocks. I don’t want recursive blocks to go away personally.
I think it’s reasonable to give block arguments argument semantics
(especially in light of the addition of &block arguments to blocks)
instead of assignment semantics. You don’t lose any power, although
you do lose some “expressivity”, eg:
a = nil
set_a = lambda { |b| a = b }
instead of
a = nil
set_a = lambda { |a| }
On 9/9/07, [email protected] [email protected] wrote:
changed ![:slight_smile: :slight_smile:](https://www.ruby-forum.com/images/emoji/apple/slight_smile.png?v=12)
p h
block parameters ![:slight_smile: :slight_smile:](https://www.ruby-forum.com/images/emoji/apple/slight_smile.png?v=12)
I agree, except for the fact that assignments are relatively static,
while ‘yield’ calls are variadic. Please tell me you don’t use this
feature, David. ![:slight_smile: :slight_smile:](https://www.ruby-forum.com/images/emoji/apple/slight_smile.png?v=12)
Hash#each do {|h[:x]| … } is… pretty strange.
Hi –
On Mon, 10 Sep 2007, Wilson B. wrote:
that this makes perfect sense, once you learn it, and should not be
f[7]
who think that there’s nothing wrong with assignment semantics for
block parameters ![:slight_smile: :slight_smile:](/images/emoji/twitter/slight_smile.png?v=6)
I agree, except for the fact that assignments are relatively static,
while ‘yield’ calls are variadic. Please tell me you don’t use this
feature, David. ![:slight_smile: :slight_smile:](/images/emoji/twitter/slight_smile.png?v=6)
Hash#each do {|h[:x]| … } is… pretty strange.
I’ve never used h[:x] as a block parameter. That is a bit exotic, and
a bit useless
But I think I’ve used an instance variable. Also
it’s handy if, for example, you want to capture the last value passed
during an iteration.
David
On 9/9/07, [email protected] [email protected] wrote:
On 9/9/07, Bernardo Monteiro R. [email protected] wrote:
feature, David. ![:slight_smile: :slight_smile:](https://www.ruby-forum.com/images/emoji/apple/slight_smile.png?v=12)
Hash#each do {|h[:x]| … } is… pretty strange.
I’ve never used h[:x] as a block parameter. That is a bit exotic, and
a bit useless
But I think I’ve used an instance variable. Also
it’s handy if, for example, you want to capture the last value passed
during an iteration.
I would be OK-er with this if method arguments obeyed the same rules.
e.g.
def foo=(@foo);end
foo = 5
would then automatically set the instance variable for you.
I think I mostly don’t like it because it is unique to block
arguments, and even then is pretty significantly different in
‘regular’ blocks vs. lambdas.
On 9/9/07, [email protected] [email protected] wrote:
Hi –
it’s handy if, for example, you want to capture the last value passed
I think I mostly don’t like it because it is unique to block
I was referring (poorly) to the fact that lambdas enforce arity but
regular blocks do not.
Hi –
On Mon, 10 Sep 2007, Wilson B. wrote:
On 9/9/07, Logan C. [email protected] wrote:
like a wild animal through the streets of your city. =(
Hey, nothing wrong with that – it’s just like
while ‘yield’ calls are variadic. Please tell me you don’t use this
I would be OK-er with this if method arguments obeyed the same rules.
e.g.
def foo=(@foo);end
foo = 5
would then automatically set the instance variable for you.
I think I mostly don’t like it because it is unique to block
arguments, and even then is pretty significantly different in
‘regular’ blocks vs. lambdas.
It’s definitely different from method-param semantics. It’s never
bothered me, though – it’s just a different decision about how block
params will work.
I’m not sure what you mean when you say different between regular
blocks and lambdas – ?
David
On Sep 9, 3:28 am, [email protected] wrote:
a = 0
Definitely not a bug. Block parameters use assignment semantics, with
regard to the scope in which the block appears. In your example,
you’re assigning 1 to a. If you create a local variable inside the
block, however, it only exists for the duration of the block.
As far as remember, Guy Decoux and I are the only two people who think
that this makes perfect sense
Does this mean that you and Guy and Matz smoked
the same wacky tobaccy?