Bug in lambda?

2007/9/9, [email protected] [email protected]:

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:

Now I’m curious: how often do you have use for this feature? I mean,
if block parameters were locally scoped you just had to punch in one
more assignment to get the same effect like the current version:

def foo
x=1
lambda {|a| x=a}
end

Do I miss something?

Kind regards

robert

Hi –

On Mon, 10 Sep 2007, Robert K. wrote:

Now I’m curious: how often do you have use for this feature? I mean,
if block parameters were locally scoped you just had to punch in one
more assignment to get the same effect like the current version:

def foo
x=1
lambda {|a| x=a}
end

Do I miss something?

I don’t think so, but part of the problem for me is that there’s no
problem – in other words, I learned that it works with assignment
syntax, and probably haven’t made all that much use of it but never
thought there was any reason for it not to work that way. I suppose
it’s possible to clobber variables, but then it’s possible to do that
without blocks, too, if you’re not careful about variable names.

David

On 9/10/07, [email protected] [email protected] wrote:

As far as remember, Guy Decoux and I are the only two people who think
end

I think that the original poster was worried that this script would
print “7”. If that’s not the case, forgive me. :slight_smile:

def do_it x, f
f.call 7
p x
end

f = lambda {|x| x}
do_it 1, f

The existing behavior seems much scarier in IRB than in ‘real’ code.

On 10.09.2007 19:05, Wilson B. wrote:

end

I think that the original poster was worried that this script would
print “7”. If that’s not the case, forgive me. :slight_smile:

def do_it x, f
f.call 7
p x
end

f = lambda {|x| x}
do_it 1, f

What output would you prefer? I don’t see how this can print “7” if
that’s what you were up to. In fact, I would be scared to see that. :slight_smile:

Actually the original issue was different IIRC, because the block was
defined in a scope which had the block parameter as a local variable
which is not the case in your example.

Kind regards

robert

On 10.09.2007 16:52, [email protected] wrote:

As far as remember, Guy Decoux and I are the only two people who think
end

Do I miss something?

I don’t think so, but part of the problem for me is that there’s no
problem – in other words, I learned that it works with assignment
syntax, and probably haven’t made all that much use of it but never
thought there was any reason for it not to work that way. I suppose
it’s possible to clobber variables, but then it’s possible to do that
without blocks, too, if you’re not careful about variable names.

Ah, ok. I suspected you had some cool usage for this which I overlooked
and could insert into my repertoire. :slight_smile:

As you say, there are many ways to shoot yourself in the foot - block
parameters are just one of them.

Kind regards

robert

I note no one has addressed my concern. I feel like there’s an
elephant in the room that only I can see :slight_smile:

Hi –

On Tue, 11 Sep 2007, Logan C. wrote:

I note no one has addressed my concern. I feel like there’s an
elephant in the room that only I can see :slight_smile:

Do you mean the thing about recursive blocks?

David

2007/9/11, Logan C. [email protected]:

I note no one has addressed my concern. I feel like there’s an
elephant in the room that only I can see :slight_smile:

I only see an otter. :slight_smile: I can see how block parameter’s scoping rules
creates the issue you demonstrated but IMHO the problem is not limited
to block parameters. As David said already, you will shoot yourself in
the foot if you do not take care when naming variables. I do agree
though that the current block parameter semantics make the situation
worse although I would not go as far as to forbid recursive block
invocations. Still, I think it is a good idea that this is being
worked on.

Kind regards

robert

From: Robert K. [mailto:[email protected]]

Actually the original issue was different IIRC, because the block was

defined in a scope which had the block parameter as a local variable

which is not the case in your example.

nonetheless, it is still dangerous on procs/lambda
these block arg var creeping scope just adds to the confusion and danger

simple example (got this fr avi’s post),

botp@pc4all:~$ irb
irb(main):001:0>
irb(main):002:0* x=“this is a test”
=> “this is a test”
irb(main):003:0> fac = lambda{|x| if x == 0 then 1 else fac.call(x - 1)

  • x end}
    => #Proc:0xb7dcda90@:3(irb)
    irb(main):004:0> puts fac.call(3)
    0
    => nil
    irb(main):005:0> quit
    botp@pc4all:~$ irb
    irb(main):001:0> fac = lambda{|x| if x == 0 then 1 else fac.call(x - 1)
  • x end}
    => #Proc:0xb7d6542c@:1(irb)
    irb(main):002:0> puts fac.call(3)
    6
    => nil

kind regards -botp

From: Robert K. [mailto:[email protected]]

On 10.09.2007 16:52, [email protected] wrote:

> I don’t think so, but part of the problem for me is that there’s no

> problem – in other words, I learned that it works with assignment

> syntax, and probably haven’t made all that much use of it but never

> thought there was any reason for it not to work that way.

I suppose

> it’s possible to clobber variables, but then it’s possible

to do that

> without blocks, too, if you’re not careful about variable names.

Ah, ok. I suspected you had some cool usage for this which I

overlooked and could insert into my repertoire. :slight_smile:

irb(main):001:0> require ‘with_index’
=> true
irb(main):002:0> a=[1,2,3,4]
=> [1, 2, 3, 4]
irb(main):007:0> i=nil
=> nil
irb(main):008:0> a[i]+=1 until a.all_w_index?{|x,i| x>3}
=> nil
irb(main):009:0> a
=> [4, 4, 4, 4]

note, that i modified #all? so i will know where the trigger was
same also with #any?..

irb(main):010:0> a=[1,2,3,4,5]
=> [1, 2, 3, 4, 5]
irb(main):011:0> a[i]+=1 while a.any_w_index?{|x,i| x<4}
=> nil
irb(main):012:0> a
=> [4, 4, 4, 4, 5]

but you can do same w scratch vars
though w an added assignment, i find it clearer…

irb(main):029:0> a=[1,2,3,4,5]
=> [1, 2, 3, 4, 5]
irb(main):030:0> even=nil
=> nil
irb(main):031:0> a[even]+=1 while a.any_w_index?{|x,i| even=i; x%2==0}
=> nil
irb(main):032:0> a
=> [1, 3, 3, 5, 5]
irb(main):033:0> odd=nil
=> nil
irb(main):034:0> a[odd]+=1 while a.any_w_index?{|x,i| odd=i; x%2!=0}
=> nil
irb(main):035:0> a
=> [2, 4, 4, 6, 6]

the idioms would be likened to,

part = nil
machine.repair(part) while machine.any?{|part| part.broken?}

and

broken = nil
machine.repair(broken) while
machine.any?{|part| (broken=part).broken?}

so that is,

  "repair part while there is any part broken"

vs
“repair broken part while there is any part broken”

your choice.

As you say, there are many ways to shoot yourself in the foot - block

parameters are just one of them.

Arggh, the scary part is you wont even know if you’ve been shot until
you’re dead --too late. I myself do not like block args (or any args for
that matter) clobbering local, global, and instance vars. Surely, it is
not the intent of the programmer to clobber them, nor is it an intuitive
intent to peek on arg values from the outside (is that being
obj-oriented?). I clobber what i clobber. When coding an arg var, surely
i do not need to bother and question myself “will this var clobber other
vars?”. Ruby should help me on that, not put fear on it. I wonder what
is the original intent of matz when he designed that feature. It is
scary. I’ve been hit by it. And now i have to be careful about naming my
vars. Is shadowing arg vars really used much in practice? It is not a
fun part of ruby if you ask me. or maybe, it is just too much fun for
me. forgive the non-ruby-hacker, pls :frowning:

kind regards -botp

On Tue, 11 Sep 2007 21:03:23 +0900, [email protected] wrote:

But you always have to avoid clobbering variables:

x = 1


x = gets

if x > 0 # blows up

I just yesterday read of a “programmer” who had that problem:

“How do I get the first value out of a variable?”

Jay

On 9/11/07, [email protected] [email protected] wrote:

I think the only hurdle is just realizing that:

{|x| … }

is an assignment to x. After that, it’s no more dangerous or
error-prone than any other occasion when you have to choose a name for
a temporary (or not) variable and assign to it.

It’s not though. It’s almost like an assignment to x, except when
it’s like passing a parameter. If it really was always just assigning
to x, my example would overflow in both cases, which while not my
personal ideal, would make me happier than the current situation.

Hi –

On Tue, 11 Sep 2007, Peña, Botp wrote:

it. And now i have to be careful about naming my vars.
Is that bad? :slight_smile:

Is shadowing
arg vars really used much in practice? It is not a fun part of ruby
if you ask me. or maybe, it is just too much fun for me. forgive the
non-ruby-hacker, pls :frowning:

But you always have to avoid clobbering variables:

x = 1


x = gets

if x > 0 # blows up

I think the only hurdle is just realizing that:

{|x| … }

is an assignment to x. After that, it’s no more dangerous or
error-prone than any other occasion when you have to choose a name for
a temporary (or not) variable and assign to it.

David

On 9/12/07, Robert K. [email protected] wrote:

a temporary (or not) variable and assign to it.
variables in blocks is that they are block local when not defined
outside of the block. This is the same regardless whether a var name
occurs between bars or on the left side of an assignment.

I’m pretty sure everything you said is factual. I still think it’s
wrong.

On 9/11/07, Jay L. [email protected] wrote:

I Didn’t Know You Could Do That! - The Daily WTF

Brilliant! Way to climb the ladder Megan!

2007/9/12, Logan C. [email protected]:

It’s not though. It’s almost like an assignment to x, except when
it’s like passing a parameter. If it really was always just assigning
to x, my example would overflow in both cases, which while not my
personal ideal, would make me happier than the current situation.

Actually I believe David is right. It is just an assignment to x
but you have to keep in mind the scoping rules of blocks. Basically
the notation |x| is just a shortcut for an assignment with a parameter
when the block is called. But the general scoping rule for local
variables in blocks is that they are block local when not defined
outside of the block. This is the same regardless whether a var name
occurs between bars or on the left side of an assignment.

Kind regards

robert