Yukihiro Matsumoto wrote:
> ...
> In summary, possible problems (and ugliness) are
> 
>   (1) a block parameter variable names appeared BEFORE the lambda.
>       Since parameters in most languages are scope local, some (or
>       even most) expect them local to the block, even if they already
>       appear in the enclosing scope.
> 
>   (2) a local variable names appeared IN the block.
>       When you are trying to use a variable local to the block, you
>       have to assure the name of a variable is not used outside of the
>       block.  You have to know all local variable names.  Although
>       it's good to know all local variable names in the method, a
>       programmer should be allowed to be lazy enough to avoid
>       searching variable names.
> 
>   (3) a local variable names appeared AFTER the lambda.
>       Since it's easy to forget about block scope rules, some (or even
>       most) expect the values of block local variables preserved after
>       the block.  When he meets the `undefined local variable' error,
>       he should go back before the block and initialize the variable.
> 
> I admit all violates the principles of least surprise.  Hmm.
> 

I thought very long about this issue (partly for the challenge), and although
I am probably missing certain aspects of this whole issue, I figured I'd give
it a showing anyway.

Currently, I think Ruby will bind a parameter to a local var automatically - 
but only if it exists. Otherwise it makes an in-block var, which is not 
available beyond the {  } scope.

But what are the cases for potentially desired uses of local and 
in-block parameters?

I think they are:

If a local var exists before a lambda, 
- it should be available to the lambda
- it should be bindable to a parameter

If you are making a lambda
a - you should have the option to bind parameter to a local var
    + makes in-block var same as local var; no name conflicts
b - you should have access to local vars you know about
c - if you don't bind a parameter to a local var, you shouldn't
have to worry about conflicts of that in-block var with the local var
    + [name conflict] either disallow using the local var you chose to not bind to
    + or, use special accessor syntax to differentiate the two
d - you should be able to make in-block vars that are limited to inside the block
    + to make it limited to the block, it can't be bound to a local var
    + you shouldn't have to worry about conflicts with local vars you use inside the block
e - you should be able to make vars inside the block that are accessible outside it
    + to make it accessible outside the block, it should have to be a local var
    + you shouldn't have to worry about conflicts with other local vars
f - you shouldn't have to know about all local vars to avoid conflicts

It seems to me that there are some conflicts that have nothing to do with implementation.
That is, mixing in-block-only vars with accessible local vars having the same name.(c/d)
Or, creating a local var inside the block that will conflict with pre-existing local vars (e)

The c/d conflict is not really a conflict, once you think about it. If you wish to use 
an in-block variable called 'x', and also a local variable called 'x', you would know 
about it. In that case, you name your in-block variable something else. But if you do not 
know about the local var 'x', then chances are you aren't planning on using it, either. 
In that case, you can make in-block 'x' such that it overshadows the local var - meaning 
that you can no longer access the local var called 'x'. 
This is in line with the {|x~| .... } construct.

Situation e, on the other hand, is a true overlap.  There simply has to be some other way
than making it a local var - otherwise you will have to keep track of all local vars!
Someone mentioned making the interpreter give a warning when you have conflicting names.
That is a good start.

But I think a solution would be to create some separate way to access in-block vars outside 
of the block (an apparent contradiction).

One way to do this would be to create a new scope access operator, or maybe adjust the 
existing one...  something like {}::x to access in-block variable 'x' outside of the block.
For this to work without confusion, it would have to be limited to the most recent block.


x=9;
[1,2,3].each{|x~| break if x==2}
p x	#-> 9
p {}::x	#-> 2

Alternatively, I suppose the same tilde thing could be used for that, too.

x=9;
[1,2,3].each{|x~| break if x==2}
p x	#-> 9
p x~	#-> 2


Ruby will automatically bind a parameter to a local var, but only if it exists.
If I know it exists or not, fine - I know what to expect.

But if I do not know whether a local var exists, I use |x~|, and either use it
only in the block, or else access it outside the block as x~, without worrying
about it conflicting with local var 'x'.

Now, about the nesting problem... the solution depends on what the desired behaviour
should be, and I have not thought long enough about that... ;-)


Guy N. Hurst

P.S. If the tilde is too ugly, then using the <a,b> combined with |x,y| and {}::x
is fine with me.

{|x,y|<a,b> a=x; ....}	# <a,b> in-block only
p {}::a			# but still accessible outside ;-)
p x			# local vars as before
etc..

vs.

{|x~,y,b~| .... }	# x,b in-block only
p x~			# in-block x still available as x~
p x  			# local vars as before...

I don't think the tilde is so bad, considering its capability...


-- 
HurstLinks Web Development    http://www.hurstlinks.com/
Norfolk, VA - (757)623-9688
PHP/MySQL - Ruby/Perl - HTML/Javascript