Hi,
Well, Matz is much smarter than I am… but this
makes me wince.
I don’t think I’m smarter than you. That’s simply my fault that I
cannot explain clear enough mostly due to the language barrier.
I wish I were born in English speaking country. I’ll try to explain
anyway.
Originally, the “|…|” used to be a simple iteration variable
specifier. But when Proc (and closure) was introduced to Ruby (back
in Ruby 0.60 in 1994), I needed block local variables, so I made the
current local variable scoping rule, which is “when a new local
variable appears first in a block, it is valid only in the block”.
And I was wrong. This rule is the single biggest design flaw in
Ruby. You have to care about local variable name conflict, and you
will have totally different result (without error) if they conflict.
So, we are talking about a part of many-year-long effort of fixing
this flaw.
We have following constraints:
-
the fix should not cause fatal compatibility problem. It may not
cause any problem, or at least may not cause any problem which
cannot be fixed by the filter program.
-
the fix need not to cover arbitrary combination of local/non-local
variables in block parameter, so that you don’t need the one like
a,{b},c| # where a goes block-local
as someone proposed before. We have two major usage of block
parameters, a) iterator variables b) closure arguments. The
current block parameters are suitable (and designed for) a. I
guess we need a new notation designed for b too.
-
preferably, the above bad scoping rule should be removed from the
language in the future, so that I guess we need a new notation to
declare in-block variables.
-
Ruby does not like explicit variable declaration (except method
arguments, of course), so that a new in-block variable declaration
is better not be explicit, if possible.
I’ve got a bunch of proposals from worldwide (and from myself). Some
seemed good, Some bad, and some even ugly. Thank you everyone who
joined the discussion anyway. After a long discussion and pondering,
there is the first design choice:
(a-1) do nothing, it’s already a part of the language even though it’s
bad. Stay as it is.
Pros: least effort.
Cons: least effectiveness.
(a-2) do something, let’s make Ruby close to the perfect language.
Assuming we choose the latter, I chose several candidates for the fix.
From the constraints, we need two new notations to fix the problem,
one for block parameters and one for in-block variables.
For block parameters (in order of my preference):
(b-1) “<…>” that takes local variables only; they are in-block
local. In addition, it follows basic rules of argument
passing, even optinal argumen may be allowed.
Pros: it solves several pitfalls of Ruby at once, for example,
"lambda{|a| p a}.call(1,2,3)" prints "[1,2,3]", because
it behaves like assignment "a = 1,2,3". on the other
hand, "lambda{<a> p a}.call(1,2,3)" will cause an error
"wrong number of arguments (3 for 1)".
Cons: it makes Ruby syntax bigger.
it appears awkward for some eyes.
(b-2) “|…|” should take local variables only, and make them
in-block variables.
Pros: it makes Ruby syntax simpler.
Cons: no backward compatibility.
For in-block variables:
(c-1) local variables assigned by “:=” are in-block variables,
otherwise they are method local variables. If you assigns to
an existing local variable, the variable is shadowed, and you
will probably be warned.
(c-2) variables listed after “;” in the block parameters are in-block
variables. If you list an existing local variable, the
variable is shadowed, and you will probably be warned.
Cons: this is explicit declaration.
(c-3) introduce a method named “let” and use the solution for (b) to
solve the in-block variables problem. For example (in the case
we choose (b-1)):
lambda{<x,y> # x,y are local to this closure.
...
let{<a,b,c>
.... # a,b,c are local here.
}
...
}
Pros: least syntax enhancement.
Cons: Cons: this is explicit declaration.
And even uglier (to my eyes).
Man, it took me hours to write this mail. Why you guys don’t read Japanese?
Complaint #1: This introduces an ordering constraint on
the items. If the “natural” order is a,b,c but we need
b to be local, we will write something like |a,c;b|
It won’t happen, since they are different things. “a” and “c” are
block parameters, “b” is an in-block variable.
Complaint #2: The <x;y> case is exceptionally annoying
to me if I understand it correctly. Doesn’t it send two
contradictory messages (to the reader) about x? The fact
that it appears on the lefthand side of the semicolon
says it’s nonlocal; but the fact it’s in brackets says
it’s local.
No. The fact that it appears on the lefthand side of the semicolon
says it’s a block parameter; and the fact it’s in brackets says it’s
in-block local. Get it?
matz.
···
In message “Re: ruby-dev summary 17252-17356” on 02/06/12, “Hal E. Fulton” hal9000@hypermetrics.com writes: