hoodwink.d enhanced


Ruby 2.0 block local variable #

by babie in inspect

Translated from matz blog, 2005-03-09

This is a topic I wanna talk about the meeting on yesterday1 but I didn’t because it didn’t warm up so much.

I’ve been thinking about Ruby’s block scope for a long time. I couldn’t single out easily in various ideas. In these days, It’s thought that I find the one hit the spot.

The specification is as follows.

  • Block parameters are only local valiables.
  • The scope of block parameter is block local.
  • If the name of block parameter is overlapped outside local variable, then it’s error.(Shugo Maeda won.)
  • You can set a variable that is enable in the block using syntax like ”; var” after block parameters.
  • Overlapping of these variables is error.
  • The scope of a variable appears first in the block is block local (according to the current).
  • The reference to the variable in which the scope used in the method has ended is warned.

Though it’s different that I’ve declared about Ruby 2.0 upto now (especially, part of strong-ed), I seem the compatibility is higher and the usability is not worsend. Especially, dblack has been opposed applying the method scope in the point of “The scope of a variable appears first” might be pleased.

Now, as a result,

3.times {|i; a|
  a = 5
  p [i, a]

is ok.

3.times {|i; a=5|
  p [i, a]

A syntax with initializing is more better. But ”|” is the operator might be in an expression. Thus,

  • We give it up.
  • Only primary one(literal, variable, expression bundled by parentheses, etc) be permitted at initialization.

It seems to become either.

As for the rest, it depends on whether we accept that the below is error or not.

3.times {|i; a=2+3|
  p [i, a]

1 Matz organized a mini meeting Meetup for The Matsue Ruby Meetup Group . Matz belongs among Matsue Ruby Meetup Group .

said on 14 Mar 2005 at 10:47

Does this mean that lambda { |@a, @b| } is not allowed anymore?

Also, I think there could appear problems with respect to code-generation when all local variables need to have unique names…

said on 14 Mar 2005 at 16:53

I can understand making a variable local to the block only. But requiring that it be unique? ICK ! NO!

said on 14 Mar 2005 at 21:38

I agree. I’d much rather they didn’t have to be unique.

said on 15 Mar 2005 at 13:34

Wait a minute. Is he saying that you must declare new variables as block parameters? Please, no.

said on 15 Mar 2005 at 17:22

sure the current method of declaring ‘shared’ variables to a block outside the block is a bit of a pain (or conversely, it can bite newbies when they use the same variable name in a block thinking it’s local to the block)... however, there have been various proposals for fixing this over the years, but the more proposals I see the more nervous they make me. I think I’m almost at the point now where I’d just prefer to keep things as they are.

said on 15 Mar 2005 at 20:58

Phil, I have to agree with you. The changes I wanted are minimal, but I’d gladly leave things where they are rather than implement what Matz is proposing here. A truly terrible idea IMHO .

said on 16 Mar 2005 at 00:47

chris2: first, instance variables will not be allowed in the block parameters. second, they should be unique, as they should be now.

daniel: you can declare block local variables, but declaration is not mandatory.

said on 16 Mar 2005 at 02:51
Maybe someone can explain why taking the view of a block having its own environment and a reference to the next-outer environment is not usable, here? Like in scheme:
 (lambda (x y)
  (set! y 6)
  (lambda (y z)
     (set! y 5)(set! x 7)
     ; the inner y is 5, now and we can refer
     ; to x, which has become 7 and z also
  ; the outer y is still 6, we cannot refer
  ; to z, only to x which is now 7

I honestly never understood why this is such a big deal in Ruby. But obviously I’m completely missing the point, here…

said on 16 Mar 2005 at 08:08

Matz, I have to admit that I don’t get it. Let’s say that I’ve got the following:

pdf = PDF::Writer.new

toc = []

  # Place a destination marker at the specified point so that it can be
  # linked to from the actual table of contents entry.
xref = lambda do |info|
  level, label = info[:params].split(/:/o)
  label = CGI.unescape(label)
  page  = pdf.which_page_number(pdf.current_page_number)
  toc << [ label, page, level ]

Will my use of pdf and toc be illegal, now? What happens if I had an “info” variable before the definition of the xref lambda? Do I need to do: xref = lambda { |info; pdf, toc| ... }?

If that’s the case, then I can safely say that I don’t like the proposal, as it will break existing code—that I just wrote, no less!—in nasty, nasty, nasty ways.

said on 16 Mar 2005 at 09:01

Austine, the code is totally valid. Don’t worry.

The points are:

  • block parameters (“info” in the example) must be unique, no shadowing.
  • if you want to make sure the variables to be block local, place their names after ”;”. shadowing will be detected as an error.
  • use of out-of-scope variables will be detected and warned.
said on 16 Mar 2005 at 09:55
Okay, to try to make sure I understand this:
xref = lambda do |info|
  page  = pdf.page_number(pdf.current_page)
In this, info must not be shadowed, but level, label, page, and toc are leaky? That is, I could do:
  puts page # => gets the page number?
To ensure that page wouldn’t be leaky, I need to do |info; page|? Or is it that page isn’t leaky (as it isn’t now), but the following would works?
page = 35
  xref = lambda do |info; page|
     page = 40
     puts page # -> 40
  puts page # -> 35
If that’s the way, I can live with that, but I agree with Dan that it would be useful to see how this might be modeled in the extension form, and the documentation on this will have to be explicitly clear.
said on 16 Mar 2005 at 15:48

I’d go for the Scheme-style block parameters as suggested above.

said on 16 Mar 2005 at 16:38

I checked the ChangeLog on 1.9. The experimental changes are in:

Wed Mar  9 18:09:51 2005  Yukihiro Matsumoto  <matz@ruby-lang.org>

        * parse.y (gettable_gen): warns if VCALL name is used as
          out-of-scope block local variable.  [EXPERIMENTAL]

        * parse.y (opt_bv_decl): add explicit block local variable
          declaration.  raises error for name conflicts.  [EXPERIMENTAL]

The best way to answer your questions would be to check the latest from CVS . I have a feeling that the original text was a bit more clear before translation.

Comments are closed for this entry.