New Local Variable Scope rule

In one of Matz’s slides at RubyConf ,

(http://www.rubyist.net/~matz/slides/rc2003/mgp00012.html)

he mentions his New Local Variable Scope rule as follows:

···

#---------------------------------------------------------------
def foo
a = nil
ary.each do |b|
# b is block local
c = b
a = b
# a and c are local to the method
end
# a and c available here
end
#---------------------------------------------------------------

I was wondering what would happen if it was written as follows:

#---------------------------------------------------------------
def foo(&block)
a=nil;
ary.each(&block)
end;

foo(lambda {|b| a=b; c=b})
#---------------------------------------------------------------

In other words, in general, what is the advantage of having variables in
closures leak out?
– shanko

“Shashank Date” sdate@everestkc.net schrieb im Newsbeitrag
news:c5id4r$22o3g$1@ID-194283.news.uni-berlin.de

In one of Matz’s slides at RubyConf ,

(http://www.rubyist.net/~matz/slides/rc2003/mgp00012.html)

he mentions his New Local Variable Scope rule as follows:

#---------------------------------------------------------------
def foo
a = nil
ary.each do |b|
# b is block local
c = b
a = b
# a and c are local to the method
end
# a and c available here
end
#---------------------------------------------------------------

I was wondering what would happen if it was written as follows:

#---------------------------------------------------------------
def foo(&block)
a=nil;
ary.each(&block)
end;

foo(lambda {|b| a=b; c=b})
#---------------------------------------------------------------

First of all both examples are erroneous IMHO because ary is not defined
in foo().

In other words, in general, what is the advantage of having variables in
closures leak out?

Your second example will not modify the a defined in foo() because the
binding takes place at the point of invocation, i.e. another scope. If
you do

def foo(&block)
a=nil;
ary.each(&block)
puts “a=#{a.inspect}”
end;

foo(lambda {|b| a=b; c=b})
puts “a*#{a.inspect}”

You’ll see
a=nil
a*

Regards

robert

Hi –

“Robert Klemme” bob.news@gmx.net writes:

“Shashank Date” sdate@everestkc.net schrieb im Newsbeitrag
news:c5id4r$22o3g$1@ID-194283.news.uni-berlin.de

In one of Matz’s slides at RubyConf ,

(http://www.rubyist.net/~matz/slides/rc2003/mgp00012.html)

he mentions his New Local Variable Scope rule as follows:

#---------------------------------------------------------------
def foo
a = nil
ary.each do |b|
# b is block local
c = b
a = b
# a and c are local to the method
end
# a and c available here
end
#---------------------------------------------------------------

I was wondering what would happen if it was written as follows:

#---------------------------------------------------------------
def foo(&block)
a=nil;
ary.each(&block)
end;

foo(lambda {|b| a=b; c=b})
#---------------------------------------------------------------

First of all both examples are erroneous IMHO because ary is not defined
in foo().

OK, OK… def ary; [1,2,3]; end :slight_smile:

In other words, in general, what is the advantage of having variables in
closures leak out?

Your second example will not modify the a defined in foo() because the
binding takes place at the point of invocation, i.e. another scope. If
you do

I think you mean the point of creation (of the closure), rather than
invocation?

def foo(&block)
a=nil;
ary.each(&block)
puts “a=#{a.inspect}”
end;

foo(lambda {|b| a=b; c=b})
puts “a*#{a.inspect}”

You’ll see
a=nil
a*

OK, but there’s still ‘c’. The new thing is the idea of a local
variable created in a block and persisting after the block exits. If
the scope that matters is where the block was created, then what
happens in this case:

def call_foo
foo(lambda{|b| c=b})
puts c # does c persist if the lambda was called?
end

David

···


David A. Black
dblack@wobblini.net

  def call_foo
    foo(lambda{|b| c=b})

    puts c # does c persist if the lambda was called?
  end

What you have written is similar to

   def call_foo
      a = lambda {|b| c = b}
      foo(a)
      puts c
   end

foo(a) don't change anything and if I've well understood : this is at
compile time that ruby will make the decision (local/block-local)

Guy Decoux

Hi –

ts decoux@moulon.inra.fr writes:

def call_foo
foo(lambda{|b| c=b})

puts c                # does c persist if the lambda was called?

end

What you have written is similar to

def call_foo
a = lambda {|b| c = b}
foo(a)
puts c
end

foo(a) don’t change anything and if I’ve well understood : this is at
compile time that ruby will make the decision (local/block-local)

OK… but what will the decision be, for ‘c’? Why would it be any
different here than for:

def foo
[1].each { c = 0 }
puts c
end

In both cases, an assignment is being made to c, visible at compile
time, in a particular scope. So, in your example (and mine), c is
created at compile time in the calling scope (call_foo). Then the
lambda is called, and c is actually assigned something.

Or is there going to be a further distinction between plain lambdas
and code blocks passed to iterators? If so, I really think it’s time
for a Block class. (Matz: you wanted more reasons… :slight_smile:

David

···


David A. Black
dblack@wobblini.net

Hi –

ts decoux@moulon.inra.fr writes:

def call_foo
foo(lambda{|b| c=b})

puts c                # does c persist if the lambda was called?

end

What you have written is similar to

def call_foo
a = lambda {|b| c = b}
foo(a)
puts c
end

foo(a) don’t change anything and if I’ve well understood : this is at
compile time that ruby will make the decision (local/block-local)

I’m really answering two of your posts, sort of – this one, and the
one where you give the 1.8 example with c=nil.

I think foo(a) does change something, in the 2.0 model. If you don’t
have foo(a), then puts c will raise an error:

def call_foo
a = lambda {|b| c = b}
puts c # error
end

This is therefore not the same as doing this in 1.8:

def call_foo
c = nil
a = lambda {|b| c = b}
puts c # OK, even if lambda never executes
end

David

···


David A. Black
dblack@wobblini.net

OK... but what will the decision be, for 'c'? Why would it be any
different here than for:

Well, write your example like this

   def call_foo
      c = nil
      foo(lambda{|b| c=b})
      puts c
   end

and you can test the result with 1.8 :slight_smile:

Guy Decoux

“David Alan Black” dblack@wobblini.net schrieb im Newsbeitrag
news:m3brluhh6y.fsf@wobblini.net

Hi –

ts decoux@moulon.inra.fr writes:

def call_foo
foo(lambda{|b| c=b})

puts c                # does c persist if the lambda was

called?

end

What you have written is similar to

def call_foo
a = lambda {|b| c = b}
foo(a)
puts c
end

foo(a) don’t change anything and if I’ve well understood : this is at
compile time that ruby will make the decision (local/block-local)

Maybe the call should’ve read “foo &a”.

OK… but what will the decision be, for ‘c’? Why would it be any
different here than for:

def foo
[1].each { c = 0 }
puts c
end

In both cases, an assignment is being made to c, visible at compile
time, in a particular scope. So, in your example (and mine), c is
created at compile time in the calling scope (call_foo). Then the
lambda is called, and c is actually assigned something.

Yes, of course. But there’s a difference between

def foo
[1].each { c = 0 }
puts c
end

and

def foo(&b)
[1].each &b
puts c
end
foo { c = 0 }

‘c’ comes into existence in the lexically surrounding scope, i.e. foo in
the first case and the calling context in the second case. There is no
magic that would make the second example print something other than ‘nil’
for ‘c’.

Or is there going to be a further distinction between plain lambdas
and code blocks passed to iterators? If so, I really think it’s time
for a Block class. (Matz: you wanted more reasons… :slight_smile:

It would certainly be intersting to hear that. Up to now I thought
‘lambda’ is merely a syntactical alias for ‘proc’ but I may be wrong here.

Regards

robert

   def call_foo
     a = lambda {|b| c = b}
     puts c # error
   end

You want to say that this will give an error

      def foo(x)
      end

      def call_foo
         foo(lambda {|b| c = b})
         puts c # error
      end

and this not ?

      def foo(x)
         x.call(24)
      end

      def call_foo
         foo(lambda {|b| c = b})
         puts c # 24
      end

Guy Decoux

def foo(&b)
  [1].each &b
  puts c
end
foo { c = 0 }

'c' comes into existence in the lexically surrounding scope, i.e. foo in
the first case and the calling context in the second case. There is no
magic that would make the second example print something other than 'nil'
for 'c'.

Well, it will just give

   in `foo': undefined local variable or method `c'

:slight_smile:

Guy Decoux

Hi –

“Robert Klemme” bob.news@gmx.net writes:

“David Alan Black” dblack@wobblini.net schrieb im Newsbeitrag
news:m3brluhh6y.fsf@wobblini.net

Hi –

ts decoux@moulon.inra.fr writes:

def call_foo
foo(lambda{|b| c=b})

puts c                # does c persist if the lambda was

called?

end

What you have written is similar to

def call_foo
a = lambda {|b| c = b}
foo(a)
puts c
end

foo(a) don’t change anything and if I’ve well understood : this is at
compile time that ruby will make the decision (local/block-local)

Maybe the call should’ve read “foo &a”.

OK… but what will the decision be, for ‘c’? Why would it be any
different here than for:

def foo
[1].each { c = 0 }
puts c
end

In both cases, an assignment is being made to c, visible at compile
time, in a particular scope. So, in your example (and mine), c is
created at compile time in the calling scope (call_foo). Then the
lambda is called, and c is actually assigned something.

Yes, of course. But there’s a difference between

def foo
[1].each { c = 0 }
puts c
end

and

def foo(&b)
[1].each &b
puts c
end
foo { c = 0 }

‘c’ comes into existence in the lexically surrounding scope, i.e. foo in
the first case and the calling context in the second case. There is no
magic that would make the second example print something other than ‘nil’
for ‘c’.

Right – see my wording above (“c is created at compile time in the
calling scope”, which means foo in your first example and top-level in
your second example, and call_foo in my call_foo example). I somehow
had the impression Guy was saying that in the call_foo example, no ‘c’
would be created in call_foo but I now don’t think he was. (That’s
what I meant when I asked why one would be different from the other.)

I still find it odd what happens in that calling scope. As I
understand it, after calling foo {|b| c = b}, you may or may not have
a variable ‘c’, depending on the behavior of foo (i.e., whether foo
does or does not call [or yield to] your block). To me, this
particular kind of dependency between scopes is strange.

Or is there going to be a further distinction between plain lambdas
and code blocks passed to iterators? If so, I really think it’s time
for a Block class. (Matz: you wanted more reasons… :slight_smile:

It would certainly be intersting to hear that. Up to now I thought
‘lambda’ is merely a syntactical alias for ‘proc’ but I may be wrong here.

No, you’re right. (‘proc’ is deprecated in favor of lambda, to avoid
the similarity in name between the non-similar Proc and proc objects.)
But see ruby-core, and probably ruby-talk too in the past; there have
been discussions about the various differences between and among Proc
objects, lambdas, and code blocks. (I’m not going to tempt fate by
trying to summarize them :slight_smile:

David

···


David A. Black
dblack@wobblini.net

Hi –

ts decoux@moulon.inra.fr writes:

def call_foo
a = lambda {|b| c = b}
puts c # error
end

You want to say that this will give an error

  def foo(x)
  end

  def call_foo
     foo(lambda {|b| c = b})
     puts c                  # error
  end

and this not ?

  def foo(x)
     x.call(24)
  end

  def call_foo
     foo(lambda {|b| c = b})
     puts c                  # 24
  end

Yes, that’s my interpretation. The other possibility, I think, is
that c would be nil in the first example, similar to the familiar case
of:

if false; a = 1; end
p a # nil

That may be what will happen:

l = lambda { a = 1 }
p a # nil (not error)

though I find that also to be strange behavior for a closure.

(Of course, I’m one of the few who think the way block variables work
pre-2.0 is fine, but that’s another story :slight_smile:

David

···


David A. Black
dblack@wobblini.net

“ts” decoux@moulon.inra.fr schrieb im Newsbeitrag
news:200404141329.i3EDTsS21496@moulon.inra.fr

def foo(&b)
[1].each &b
puts c
end
foo { c = 0 }

‘c’ comes into existence in the lexically surrounding scope, i.e. foo
in
the first case and the calling context in the second case. There is
no
magic that would make the second example print something other than
‘nil’
for ‘c’.

Well, it will just give

in foo': undefined local variable or method c’

Exactly.

robert

That may be what will happen:

  l = lambda { a = 1 }
  p a # nil (not error)

Well, this is what I've trying to say

     l = lambda { a = 1 } # 2.0

is similar to

     a = nil
     l = lambda { a = 1 } # 1.8

(Of course, I'm one of the few who think the way block variables work
pre-2.0 is fine, but that's another story :slight_smile:

  1) confuse some persons, which see |a, b| as a declaration rather than an
     assignement

  2) there are really 2 different uses for block-local variable. In an
     iterator probably you'll expect the 2.0 behaviour, in a Thread (or
     perhaps a Proc) probably you expect the 1.8 behaviour

Guy Decoux

I wish someone would summarize them. The inevitable difficulty of
doing so would demonstrate what to my mind is obvious: the complexity
is getting way out of hand!

I’ve forgotten what the motivation for splitting apart a seemingly
unified concept is.

Gavin

···

On Thursday, April 15, 2004, 7:14:11 PM, David wrote:

It would certainly be intersting to hear that. Up to now I thought
‘lambda’ is merely a syntactical alias for ‘proc’ but I may be wrong here.

No, you’re right. (‘proc’ is deprecated in favor of lambda, to avoid
the similarity in name between the non-similar Proc and proc objects.)
But see ruby-core, and probably ruby-talk too in the past; there have
been discussions about the various differences between and among Proc
objects, lambdas, and code blocks. (I’m not going to tempt fate by
trying to summarize them :slight_smile:

Hi –

ts decoux@moulon.inra.fr writes:

That may be what will happen:

l = lambda { a = 1 }
p a # nil (not error)

Well, this is what I’ve trying to say

 l = lambda { a = 1 } # 2.0

is similar to

 a = nil
 l = lambda { a = 1 } # 1.8

I guess I’ve been trying to have it be something else because I
dislike that so much (the 2.0 version).

(Of course, I’m one of the few who think the way block variables work
pre-2.0 is fine, but that’s another story :slight_smile:

  1. confuse some persons, which see |a, b| as a declaration rather than an
    assignement

I wish they would just learn it :slight_smile: But of course Matz has decided he
doesn’t like it, so that’s that.

  1. there are really 2 different uses for block-local variable. In an
    iterator probably you’ll expect the 2.0 behaviour, in a Thread (or
    perhaps a Proc) probably you expect the 1.8 behaviour

That’s why I was asking earlier whether this is a further difference
between Procs and blocks. For example:

2.0

def x
pr = Proc.new { a = 1 }
l = lambda { b = 1 }
# do we have a and b defined here, or just b?
end

Or when you say ‘expect’, do you mean ‘expect, but not receive’? :slight_smile:

David

···


David A. Black
dblack@wobblini.net

I agree… I can’t help but think that these things could be simplified
and condensed back into a unified concept. But, right now we have: Proc
objects, lambdas, and code blocks. And they behave differently in
things like Class.new, define_method, instance_eval, etc…

What if there were different attributes of blocks that could be
modified, so that all the different usages could be combined? ie,
Proc#uses_locals, Proc#checks_arity, etc.

This is just a kinda spur of the moment solution; there is probably a
big hole or two in the idea. Anyone with more knowledge about Ruby’s
guts care to comment?

cheers,
–Mark

···

On Apr 15, 2004, at 7:01 AM, Gavin Sinclair wrote:

On Thursday, April 15, 2004, 7:14:11 PM, David wrote:

It would certainly be intersting to hear that. Up to now I thought
‘lambda’ is merely a syntactical alias for ‘proc’ but I may be wrong
here.

No, you’re right. (‘proc’ is deprecated in favor of lambda, to avoid
the similarity in name between the non-similar Proc and proc objects.)
But see ruby-core, and probably ruby-talk too in the past; there have
been discussions about the various differences between and among Proc
objects, lambdas, and code blocks. (I’m not going to tempt fate by
trying to summarize them :slight_smile:

I wish someone would summarize them. The inevitable difficulty of
doing so would demonstrate what to my mind is obvious: the complexity
is getting way out of hand!

I’ve forgotten what the motivation for splitting apart a seemingly
unified concept is.

I guess I've been trying to have it be something else because I
dislike that so much (the 2.0 version).

Well, if I've well understtod you still have the possibility to write

   l = lambda { local {|a| a = 1} } # ugly ???

    pr = Proc.new { a = 1 }
    l = lambda { b = 1 }

and what do you do with this ?

       Thread.new { a = 1 } # like Proc or like lambda ?
       NewClass.new { a = 1 } # like Proc or like lambda ?
       new_method { a = 1 } # like Proc or like lambda ?

Guy Decoux

“David Alan Black” dblack@wobblini.net schrieb im Newsbeitrag
news:m33c75o1oc.fsf@wobblini.net

Hi –

ts decoux@moulon.inra.fr writes:

That may be what will happen:

l = lambda { a = 1 }
p a # nil (not error)

Well, this is what I’ve trying to say

 l = lambda { a = 1 } # 2.0

is similar to

 a = nil
 l = lambda { a = 1 } # 1.8

I guess I’ve been trying to have it be something else because I
dislike that so much (the 2.0 version).

(Of course, I’m one of the few who think the way block variables
work
pre-2.0 is fine, but that’s another story :slight_smile:

  1. confuse some persons, which see |a, b| as a declaration rather
    than an
    assignement

I wish they would just learn it :slight_smile: But of course Matz has decided he
doesn’t like it, so that’s that.

  1. there are really 2 different uses for block-local variable. In an
    iterator probably you’ll expect the 2.0 behaviour, in a Thread
    (or
    perhaps a Proc) probably you expect the 1.8 behaviour

That’s why I was asking earlier whether this is a further difference
between Procs and blocks. For example:

2.0

def x
pr = Proc.new { a = 1 }
l = lambda { b = 1 }
# do we have a and b defined here, or just b?
end

Why would we have anything defined here although both blocks are not
executed in this example? Slowly I’m loosing grips here… A summary was
definitely in order.

I used to be confused, but now I’m not sure anymore.

robert

Hi –

ts decoux@moulon.inra.fr writes:

I guess I’ve been trying to have it be something else because I
dislike that so much (the 2.0 version).

Well, if I’ve well understtod you still have the possibility to write

l = lambda { local {|a| a = 1} } # ugly ???

I admit I’m confused by this. Is ‘local’ being introduced? And if

a> is a block variable, isn’t it local to the block anyway?

pr = Proc.new { a = 1 }
l = lambda { b = 1 }

and what do you do with this ?

   Thread.new { a = 1 }    # like Proc or like lambda ?
   NewClass.new { a = 1 }  # like Proc or like lambda ?
   new_method { a = 1 }    # like Proc or like lambda ?

I’m not sure what you mean. Do you mean what would I do if I were
designing Ruby 2.0, or what do I think Matz will have them do? I
don’t know, since I still don’t know the answer to the above (whether
Proc and lambda will be different in this respect). I think maybe you
think that I know, but I don’t :slight_smile:

David

···


David A. Black
dblack@wobblini.net