ideas for an RCR: variable locality

E

Eric Mahurin

I would like to start this thread with end goal being to create
an RCR to control variable locality in the language (or
determine that there is already a reasonable alternative).

Problem: Within a method you can't reuse a variable name for a
local variable. Some changes in ruby 2 may help the issue, but
also hurt it in another way.

Example: For performance reasons, I'm having my package
(grammar - generic parser), generate flattened (reduce
calls/stack depth) code. As long as each "method" (to be
flattened) is simple enough that it doesn't require local
variables I'm OK. But as soon one of these need a local
variable, I'm in trouble - that variable could step on the toes
of another including one just like it that it calls/flattens.

Possible solutions:

1. Do nothing in the language. Ruby coders should architect
around the problem and accept any limitations. A possible
solution to the above problem would be to use a stack (Array)
for each of these local variables to manually get locality - or
ignore performance issues.

2. Take advantage of the fact that in Ruby 2 block arguments
are always local. A localize method could be created that call
a block and that block would make the variables that it wanted
local arguments to the block. Unfortunately, this solution
doesn't help the performance issue above - it worsens it using
at least 2 call levels.

x =3D 0
a,b =3D 1,2
z =3D localize { |x,y| # doesn't modify outside x
x =3D a+b # use a and b from outside
y =3D a-b
x*y
}

3. Use "def" to make a method (dummy unused name - _local) on
the fly and call it. Any variables that the code needed would
have to be passed in as arguments since all variables inside
would be local. Sort of an opposite approach #2 where the
arguments are local and everything else inside has the same
scope. This is doable with no change to the language, but is
quite ugly and has performance issues.

x =3D 0
a,b =3D 1,2
def _local(a,b)
x =3D a+b
y =3D a-b
x*y
end
z =3D _local(a,b)

4. Have a new block syntax to localize variables inside - maybe
{{ ... }} instead of { ... }. Too be more convenient than #3,
you'd want an easy way to grab variables in the containing
scope. When the code tries to read a local variable not yet
defined, it would get the value from the variable of the same
name in the containing scope.

x =3D 0
a,b =3D 1,2
z =3D lambda {{
# all variables inside here are local
# initialize a/b from outside since not defined
x =3D a+b
y =3D a-b
x*y
}}.call # could have a method do the call for you

5. New localizing construct. This construct would be to
begin/end as the above #4 {{...}} would be to plain blocks.=20
The same handling of undefined local variables would occur
(intialize from outside).

x =3D 0
a,b =3D 1,2
# reuse module keyword to prevent new keyword conflicts
z =3D module=20
x =3D a+b
y =3D a-b
x*y
end

6. Make "module" (and probably "class" and "def") handle
reading an undefined local variable like #4 and #5 (instead of
raising an exception immediately, try initializing it from the
containing scope). With this, we could use an unused dummy
module name to solve the problem at hand (in addition to adding
flexibility to do other things):

x =3D 0
a,b =3D 1,2
z =3D module Dummy
x =3D a+b
y =3D a-b
x*y
end

Personally, I'd like to see #4, #5, and #6, but any of those 3
might do (#4 if there was a fast builtin block evaluator - no
additional stack depth).

Any opinions on the topic? Any other ideas?


__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around=20
http://mail.yahoo.com=20
 
T

Trans

Peter and I have discussed for Suby. We haven't had a conclusion. I
last proposed:

z = lambda [
...
]

And a way to share vars from the above scope specifically:

z = lambda [
share :x
]

Since hash and block share literal deliminators, it only seems fair
that array do the same ;-)

T.
 
L

Linus Sellberg

------=_Part_6637_26146152.1128192797250
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

z =3D lambda [
share :x
]


Wouldn't it make sense to let the most common wanted behaviour be the
default? That is, letting the block inherit the variables but letting it be
possible to not share as well, if that is wanted?

------=_Part_6637_26146152.1128192797250--
 
B

Bob Hutchison

Problem: Within a method you can't reuse a variable name for a
local variable. Some changes in ruby 2 may help the issue, but
also hurt it in another way.

Example: For performance reasons, I'm having my package
(grammar - generic parser), generate flattened (reduce
calls/stack depth) code. As long as each "method" (to be
flattened) is simple enough that it doesn't require local
variables I'm OK. But as soon one of these need a local
variable, I'm in trouble - that variable could step on the toes
of another including one just like it that it calls/flattens.

Possible solutions:

x = 0
a,b = 1,2
z = localize { |x,y| # doesn't modify outside x
x = a+b # use a and b from outside
y = a-b
x*y
}


Any opinions on the topic? Any other ideas?

It seems that all of your suggests require a change to Ruby, so,
keeping that in mind...

Something like:

x = 0
a,b = 1,2
z = { |x, y|
x = a + b
y = a - b
x * y
}

would be my preference, but that would break existing code. So maybe
something like:

x = 0
a,b = 1,2
z = %M{ |x, y|
x = a + b
y = a - b
x * y
}

(the letter in the %M doesn't matter, but that's the idea)

I'll point out that this is a very similar problem to what languages
with advanced macro capabilities (e.g. Common Lisp) have had to
solve. The mechanism CL used is 'quasi-quote' with a syntactic
abbreviation of '`' (a back quote). Inside quasi-quoted text if a ','
is encountered the value of that variable is substituted in.

Anyway, so this got me thinking along those lines. This code works in
Ruby right now...

module Gensym
@@gensym_count = 0
def Gensym.gensym(prefix="gensym")
#generates a unique name with the given prefix
@@gensym_count += 1
return sprintf("%s_%s", prefix, @@gensym_count)
end
end

def compute_z_macro(x=Gensym.gensym, y=Gensym.gensym)
return %Q{
#{x} = a + b
#{y} = a - b
#{x} * #{y}
}
end

def go
x = 0
a,b = 1,2
z = eval compute_z_macro
printf("x = %d, z = %d\n", x, z)

z = eval compute_z_macro("x")
printf("x = %d, z = %d\n", x, z)

puts compute_z_macro
puts compute_z_macro("x")
end

go

There are no local variables created when the eval is executed (this
is very good)

And with some changes to Ruby (defmacro, automatic call to gensym if
no parameter value provided, using the ',' notation rather than #{}, %
M, automatic call to eval when the 'call' of the macro happens, not-
evaluating parameters to the macro)

defmacro compute_z(x, y)
return %M{
,x = a + b
,y = a - b
,x * ,y
}
end

def go
x = 0
a,b = 1,2
z = compute_z
printf("x = %d, z = %d\n", x, z)

z = compute_z(x)
printf("x = %d, z = %d\n", x, z)
end


Anyway, you have macros at the same time. A little far from what you
were asking but...

Cheers,
Bob
 
E

Eric Mahurin

--- Trans said:
And a way to share vars from the above scope specifically:
=20
z =3D lambda [
share :x
]

I was hoping to not bring in any type of variable declaration
syntax (like perl's my/our/local) into play. I was also
thinking that this type of block would have no write access to
the variables in the surrounding scope (block would need to
return data instead). You could give read-only access when the
block accesses one of its variables not yet assigned to (get
the value from the containing scope):

x =3D 1+2
z =3D lambda {{
# becomes equivalent to y =3D (x=3D3) when compiled
y =3D x
}}

Hopefully this could be done in such a way so that once that
block is created it doesn't need access to its containing scope
anymore and you don't have to worry about the block preventing
GCing stuff in that scope (as you do with normal blocks).=20
Although you wouldn't be able to get the Binding of this type
of block, you would still want to have a way to get the file,
line, (and column?) of where the block was created.
Since hash and block share literal deliminators, it only
seems fair
that array do the same ;-)

But [] is also an operator and {} is not. To use [] for a
different type of block, you'd have to differentiate between it
and the [] operator based on spacing - which I think is bad.



=09
__________________________________=20
Yahoo! Mail - PC Magazine Editors' Choice 2005=20
http://mail.yahoo.com
 
E

ES

Eric said:
I would like to start this thread with end goal being to create
an RCR to control variable locality in the language (or
determine that there is already a reasonable alternative).

Problem: Within a method you can't reuse a variable name for a
local variable. Some changes in ruby 2 may help the issue, but
also hurt it in another way.

Example: For performance reasons, I'm having my package
(grammar - generic parser), generate flattened (reduce
calls/stack depth) code. As long as each "method" (to be
flattened) is simple enough that it doesn't require local
variables I'm OK. But as soon one of these need a local
variable, I'm in trouble - that variable could step on the toes
of another including one just like it that it calls/flattens.

Could you perhaps offer a reduced code example? Your problem
description makes no sense (though probably due to fault of
mine).
[snip solutions]

E
 
T

Trans

Eric said:
--- Trans said:
And a way to share vars from the above scope specifically:

z = lambda [
share :x
]

I was hoping to not bring in any type of variable declaration
syntax (like perl's my/our/local) into play.

I undertsnad but then you start getting into more syntax hacks like {
|x,y; z|... }. That;s even worse. At least the above is simple and
clear.
I was also
thinking that this type of block would have no write access to
the variables in the surrounding scope (block would need to
return data instead).

Yes, I am too. You'd have to use #share to open a variable up.
You could give read-only access when the
block accesses one of its variables not yet assigned to (get
the value from the containing scope):

x = 1+2
z = lambda {{
# becomes equivalent to y = (x=3) when compiled
y = x
}}

That's cool. So you'd really only need a way to "send it out". hmmm..
#share cuold work for that, it's would then be more like #return
instead of a declaration.
Hopefully this could be done in such a way so that once that
block is created it doesn't need access to its containing scope
anymore and you don't have to worry about the block preventing
GCing stuff in that scope (as you do with normal blocks).
Although you wouldn't be able to get the Binding of this type
of block, you would still want to have a way to get the file,
line, (and column?) of where the block was created.
Since hash and block share literal deliminators, it only
seems fair
that array do the same ;-)

But [] is also an operator and {} is not. To use [] for a
different type of block, you'd have to differentiate between it
and the [] operator based on spacing - which I think is bad.

That's true. But hey let's open up {} as an operator too. I'm not
afraid of the spacebar! Besides I never put spaces before my []
operators anyway, and really who does?

T.
 
E

Eric Mahurin

--- ES said:
calls/flattens.
=20
Could you perhaps offer a reduced code example? Your problem
description makes no sense (though probably due to fault of
mine).

Here's one - a poor man's macro facility. Let's say a macro is
just a lambda that returns a string. You just eval it when you
need to execute the code for that macro.

plus =3D lambda { |a,b| "(#{a}+#{b})" }
# will have to re-evaluate a or b if they are an expression
min1 =3D lambda { |a,b| "(#{a}<#{b} ? #{a} : #{b})" }
# use local variables to prevent re-evaluation
min2 =3D lambda { |a,b| "(a=3D#{a};b=3D#{b};a<b ? a : b)" }

# y+z may get evaluated twice
min1["x",plus["y","z"]]
# =3D> "(x<(y+z) ? x : (y+z))"

# y+z may evaluated once
min2["x",plus["y","z"]]
# =3D> "(a=3Dx;b=3D(y+z);a<b ? a : b)"

# need to localize a/b for the inner min2
min2["x",min2["y","z"]]
# =3D> "(a=3Dx;b=3D(a=3Dy;b=3Dz;a<b ? a : b);a<b ? a : b)"


See the problem on this last example? We really need to
localize a and b. There isn't a good facility to do this.



=09
__________________________________=20
Yahoo! Mail - PC Magazine Editors' Choice 2005=20
http://mail.yahoo.com
 
B

Bob Hutchison

Eric Mahurin wrote:


for a


calls/flattens.

Could you perhaps offer a reduced code example? Your problem
description makes no sense (though probably due to fault of
mine).

Here's one - a poor man's macro facility. Let's say a macro is
just a lambda that returns a string. You just eval it when you
need to execute the code for that macro.

plus = lambda { |a,b| "(#{a}+#{b})" }
# will have to re-evaluate a or b if they are an expression
min1 = lambda { |a,b| "(#{a}<#{b} ? #{a} : #{b})" }
# use local variables to prevent re-evaluation
min2 = lambda { |a,b| "(a=#{a};b=#{b};a<b ? a : b)" }

# y+z may get evaluated twice
min1["x",plus["y","z"]]
# => "(x<(y+z) ? x : (y+z))"

# y+z may evaluated once
min2["x",plus["y","z"]]
# => "(a=x;b=(y+z);a<b ? a : b)"

# need to localize a/b for the inner min2
min2["x",min2["y","z"]]
# => "(a=x;b=(a=y;b=z;a<b ? a : b);a<b ? a : b)"


See the problem on this last example? We really need to
localize a and b. There isn't a good facility to do this.

You need gensym as lisp has (and I had in a previous example), in
which case you get this back on the last example, and there is no
problem:

(a_1=x;b_2=(a_3=y;b_4=z;a_3<b_4 ? a_3 : b_4);a_1<b_2 ? a_1 : b_2)
 
E

ES

Eric said:
for a


calls/flattens.

Could you perhaps offer a reduced code example? Your problem
description makes no sense (though probably due to fault of
mine).


Here's one - a poor man's macro facility. Let's say a macro is
just a lambda that returns a string. You just eval it when you
need to execute the code for that macro.

plus = lambda { |a,b| "(#{a}+#{b})" }
# will have to re-evaluate a or b if they are an expression
min1 = lambda { |a,b| "(#{a}<#{b} ? #{a} : #{b})" }
# use local variables to prevent re-evaluation
min2 = lambda { |a,b| "(a=#{a};b=#{b};a<b ? a : b)" }

# y+z may get evaluated twice
min1["x",plus["y","z"]]
# => "(x<(y+z) ? x : (y+z))"

# y+z may evaluated once
min2["x",plus["y","z"]]
# => "(a=x;b=(y+z);a<b ? a : b)"

# need to localize a/b for the inner min2
min2["x",min2["y","z"]]
# => "(a=x;b=(a=y;b=z;a<b ? a : b);a<b ? a : b)"


See the problem on this last example? We really need to
localize a and b. There isn't a good facility to do this.

Well, I would have to say in that case the main problem is
the design itself.

However, I think I see the issue: you mean *block-local* variables,
right, not regular local variables? As in,

foo = 5
bar = lambda {|foo| foo += 1} # Should be a local foo, not the above?

E
 
E

Eric Mahurin

--- ES said:
Eric said:
=20
=20
Eric Mahurin wrote:

I would like to start this thread with end goal being to

create

an RCR to control variable locality in the language (or
determine that there is already a reasonable alternative).

Problem: Within a method you can't reuse a variable name

for a

local variable. Some changes in ruby 2 may help the issue,

but

also hurt it in another way.

Example: For performance reasons, I'm having my package
(grammar - generic parser), generate flattened (reduce
calls/stack depth) code. As long as each "method" (to be
flattened) is simple enough that it doesn't require local
variables I'm OK. But as soon one of these need a local
variable, I'm in trouble - that variable could step on the

toes

of another including one just like it that it

calls/flattens.

Could you perhaps offer a reduced code example? Your problem
description makes no sense (though probably due to fault of
mine).
=20
=20
Here's one - a poor man's macro facility. Let's say a macro is
just a lambda that returns a string. You just eval it when you
need to execute the code for that macro.
=20
plus =3D lambda { |a,b| "(#{a}+#{b})" }
# will have to re-evaluate a or b if they are an expression
min1 =3D lambda { |a,b| "(#{a}<#{b} ? #{a} : #{b})" }
# use local variables to prevent re-evaluation
min2 =3D lambda { |a,b| "(a=3D#{a};b=3D#{b};a<b ? a : b)" }
=20
# y+z may get evaluated twice
min1["x",plus["y","z"]]
# =3D> "(x<(y+z) ? x : (y+z))"
=20
# y+z may evaluated once
min2["x",plus["y","z"]]
# =3D> "(a=3Dx;b=3D(y+z);a<b ? a : b)"
=20
# need to localize a/b for the inner min2
min2["x",min2["y","z"]]
# =3D> "(a=3Dx;b=3D(a=3Dy;b=3Dz;a<b ? a : b);a<b ? a : b)"
=20
=20
See the problem on this last example? We really need to
localize a and b. There isn't a good facility to do this.
=20
Well, I would have to say in that case the main problem is
the design itself.

I just wanted to give a simple example where having some kind
of local variable facility would easily solve the problem. In
many other cases, you can simply choose an unused name to solve
the problem (the case you have below).
However, I think I see the issue: you mean *block-local*
variables,
right, not regular local variables? As in,
=20
foo =3D 5
bar =3D lambda {|foo| foo +=3D 1} # Should be a local foo,
not the above?

This particular issue should be fixed in Ruby 2 from my
understanding - block arguments will ALWAYS be local. I'm
really talking about localizing other variables in a block and
localizing variables in something like a begin/end block.

So, in the example above, my module/end proposal would look
something like this:

min2 =3D lambda { |a,b| "module;a=3D#{a};b=3D#{b};a<b ? a : b;end" }

min2["x",min2["y","z"]]
# =3D> "module;a=3Dx;b=3Dmodule;a=3Dy;b=3Dz;a<b ? a : b;end;a<b ? a :
b;end"

Again, my module/end proposal would localize all variables
inside, but would use an external value when reading a local
variable not yet defined. I proposed to reuse "module" to not
create a new keyword, but something else could be used.

And on the block side, I proposed a new block format ({{...}})
which would do the same for variables inside the block. In
ruby 2, the default block will have all variables scoped at the
same as what contains the block.



=09
__________________________________=20
Yahoo! Mail - PC Magazine Editors' Choice 2005=20
http://mail.yahoo.com
 
E

Eric Mahurin

--- Bob Hutchison said:
Here's one - a poor man's macro facility. Let's say a macro is
just a lambda that returns a string. You just eval it when you
need to execute the code for that macro.

plus =3D lambda { |a,b| "(#{a}+#{b})" }
# will have to re-evaluate a or b if they are an expression
min1 =3D lambda { |a,b| "(#{a}<#{b} ? #{a} : #{b})" }
# use local variables to prevent re-evaluation
min2 =3D lambda { |a,b| "(a=3D#{a};b=3D#{b};a<b ? a : b)" }

# y+z may get evaluated twice
min1["x",plus["y","z"]]
# =3D> "(x<(y+z) ? x : (y+z))"

# y+z may evaluated once
min2["x",plus["y","z"]]
# =3D> "(a=3Dx;b=3D(y+z);a<b ? a : b)"

# need to localize a/b for the inner min2
min2["x",min2["y","z"]]
# =3D> "(a=3Dx;b=3D(a=3Dy;b=3Dz;a<b ? a : b);a<b ? a : b)"


See the problem on this last example? We really need to
localize a and b. There isn't a good facility to do this.
=20
You need gensym as lisp has (and I had in a previous
example), in =20
which case you get this back on the last example, and there
is no =20
problem:
=20
(a_1=3Dx;b_2=3D(a_3=3Dy;b_4=3Dz;a_3<b_4 ? a_3 : b_4);a_1<b_2 ? a_1 :
b_2)

Yes, something like this would work (using your Gensym module):

min2 =3D lambda { |a,b|
v1 =3D Gensym.gensym
v2 =3D Gensym.gensym
"(#{v1}=3D#{a};#{v2}=3D#{b};#{v1}<#{v2} ? #{v1} : #{v2})"
}

Here are the disadvantages of this compared to having ruby do
local variables:

- not as natural/uglier
- clutters the namespace/variable table
- prevents GC from freeing objects that these variables
reference




=09
__________________________________=20
Yahoo! Mail - PC Magazine Editors' Choice 2005=20
http://mail.yahoo.com
 
B

Bob Hutchison

Here's one - a poor man's macro facility. Let's say a
macro is


just a lambda that returns a string. You just eval it when


you



need to execute the code for that macro.

plus = lambda { |a,b| "(#{a}+#{b})" }
# will have to re-evaluate a or b if they are an expression
min1 = lambda { |a,b| "(#{a}<#{b} ? #{a} : #{b})" }
# use local variables to prevent re-evaluation
min2 = lambda { |a,b| "(a=#{a};b=#{b};a<b ? a : b)" }

# y+z may get evaluated twice
min1["x",plus["y","z"]]
# => "(x<(y+z) ? x : (y+z))"

# y+z may evaluated once
min2["x",plus["y","z"]]
# => "(a=x;b=(y+z);a<b ? a : b)"

# need to localize a/b for the inner min2
min2["x",min2["y","z"]]
# => "(a=x;b=(a=y;b=z;a<b ? a : b);a<b ? a : b)"


See the problem on this last example? We really need to
localize a and b. There isn't a good facility to do this.

You need gensym as lisp has (and I had in a previous
example), in
which case you get this back on the last example, and there
is no
problem:

(a_1=x;b_2=(a_3=y;b_4=z;a_3<b_4 ? a_3 : b_4);a_1<b_2 ? a_1 :
b_2)

Yes, something like this would work (using your Gensym module):

min2 = lambda { |a,b|
v1 = Gensym.gensym
v2 = Gensym.gensym
"(#{v1}=#{a};#{v2}=#{b};#{v1}<#{v2} ? #{v1} : #{v2})"
}

Here are the disadvantages of this compared to having ruby do
local variables:

- not as natural/uglier

No argument there at all, I agree. However a little syntactic sugar
would make all the difference. I made a suggestion off the top of my
head as to what that might look like, but I've got no doubt that that
can be improved.

You might be able to make an argument that local variables are more
fundamental and that a macro system shouldn't be the way to solve the
problem. Though, the problem that motivated this discussion, which I
believe amounted to a problem with in-lining functions, is probably
better solved by the macro system.


- clutters the namespace/variable table

Actually it doesn't in the current ruby. In the example I gave
earlier the gensymed names are not visible outside the eval.


- prevents GC from freeing objects that these variables
reference

Not if they don't exist (as I think they don't)


And the advantage is that you'd have a macro system

Cheers,
Bob
 
E

ES

Eric said:
Eric said:
Eric Mahurin wrote:


I would like to start this thread with end goal being to

create


an RCR to control variable locality in the language (or
determine that there is already a reasonable alternative).

Problem: Within a method you can't reuse a variable name

for a


local variable. Some changes in ruby 2 may help the
issue,

but


also hurt it in another way.

Example: For performance reasons, I'm having my package
(grammar - generic parser), generate flattened (reduce
calls/stack depth) code. As long as each "method" (to be
flattened) is simple enough that it doesn't require local
variables I'm OK. But as soon one of these need a local
variable, I'm in trouble - that variable could step on the

toes


of another including one just like it that it

calls/flattens.

Could you perhaps offer a reduced code example? Your
problem

description makes no sense (though probably due to fault of
mine).


Here's one - a poor man's macro facility. Let's say a

macro is
just a lambda that returns a string. You just eval it when
you

need to execute the code for that macro.

plus = lambda { |a,b| "(#{a}+#{b})" }
# will have to re-evaluate a or b if they are an expression
min1 = lambda { |a,b| "(#{a}<#{b} ? #{a} : #{b})" }
# use local variables to prevent re-evaluation
min2 = lambda { |a,b| "(a=#{a};b=#{b};a<b ? a : b)" }

# y+z may get evaluated twice
min1["x",plus["y","z"]]
# => "(x<(y+z) ? x : (y+z))"

# y+z may evaluated once
min2["x",plus["y","z"]]
# => "(a=x;b=(y+z);a<b ? a : b)"

# need to localize a/b for the inner min2
min2["x",min2["y","z"]]
# => "(a=x;b=(a=y;b=z;a<b ? a : b);a<b ? a : b)"


See the problem on this last example? We really need to
localize a and b. There isn't a good facility to do this.

Well, I would have to say in that case the main problem is
the design itself.


I just wanted to give a simple example where having some kind
of local variable facility would easily solve the problem. In
many other cases, you can simply choose an unused name to solve
the problem (the case you have below).

However, I think I see the issue: you mean *block-local*
variables,
right, not regular local variables? As in,

foo = 5
bar = lambda {|foo| foo += 1} # Should be a local foo,
not the above?


This particular issue should be fixed in Ruby 2 from my
understanding - block arguments will ALWAYS be local. I'm
really talking about localizing other variables in a block and
localizing variables in something like a begin/end block.

So, in the example above, my module/end proposal would look
something like this:

min2 = lambda { |a,b| "module;a=#{a};b=#{b};a<b ? a : b;end" }

min2["x",min2["y","z"]]
# => "module;a=x;b=module;a=y;b=z;a<b ? a : b;end;a<b ? a :
b;end"

Again, my module/end proposal would localize all variables
inside, but would use an external value when reading a local
variable not yet defined. I proposed to reuse "module" to not
create a new keyword, but something else could be used.

And on the block side, I proposed a new block format ({{...}})
which would do the same for variables inside the block. In
ruby 2, the default block will have all variables scoped at the
same as what contains the block.

Ah.. er.

Some kind of automatic name mangling to avoid binding?

I mean, I just do not see where this would cause any problems apart
from when one is defining a block locally in which case one should
take care not to trample on the local namespace anyway. Typically
being able to access the enclosing scope is much more valuable.

This seems like a very special-use-case and would probably just
warrant a library of some sort at most.


E
 
T

Trans

Eric said:
Again, my module/end proposal would localize all variables
inside, but would use an external value when reading a local
variable not yet defined. I proposed to reuse "module" to not
create a new keyword, but something else could be used.

I don't think reusing 'module' this way is a good idea. Modules don;t
grad varaible from outside there scope.
And on the block side, I proposed a new block format ({{...}})
which would do the same for variables inside the block. In
ruby 2, the default block will have all variables scoped at the
same as what contains the block.

{{ }} is ambigous too as an empty hash in a block.

T.
 
E

Eric Mahurin

--- Trans said:
=20
Eric Mahurin wrote:
=20
=20
I don't think reusing 'module' this way is a good idea.
Modules don;t
grad varaible from outside there scope.

I don't particularly like using the word "module" either, but I
was hoping to find a way of not adding a new keyword since
anywhere using that new keyword currently as a variable or
method name would be a problem. Another options would be
do/end, but this could get too easily confused with a block.=20
module/end seemed to be a pretty close fit because module/end
already localizes variables and executes code immediately.=20
Another option would be to have another form of begin/end -
maybe "begin:"/end. I don't know. Or give up and have a new
keyword.
=20
{{ }} is ambigous too as an empty hash in a block.

Similar ambiguity to your [] proposal. It would depend on
spacing. "{{" (localized block) would be treated differently
to "{ {" (hash in a block). This could be done at the lexer -
"{{" would be a token.

It is very hard to propose anything in the block/lambda area
without something being ambiguous because of anonymous hashes.


__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around=20
http://mail.yahoo.com=20
 
E

Eric Mahurin

--- Bob Hutchison said:
=20
No argument there at all, I agree. However a little syntactic
sugar =20
would make all the difference. I made a suggestion off the
top of my =20
head as to what that might look like, but I've got no doubt
that that =20
can be improved.
=20
You might be able to make an argument that local variables
are more =20
fundamental and that a macro system shouldn't be the way to
solve the =20
problem. Though, the problem that motivated this discussion,
which I =20
believe amounted to a problem with in-lining functions, is
probably =20
better solved by the macro system.

For my exact situation (parser generator), I don't think the
lisp-style macros would help me. My "macros" are more
object-oriented and dynamic in nature. But, I would like to
think about it a little more to see if there would be a
general-purpose macro system that could encompass the usage I
have.
=20
Actually it doesn't in the current ruby. In the example I
gave =20
earlier the gensymed names are not visible outside the eval.

Maybe you are thinking of blocks. Looks like eval uses/makes
variables in the surrounding scope:

x,y,z =3D 1,-2,3
# =3D> [1, -2, 3]
local_variables
# =3D> ["_", "x", "y", "z"]
eval "(a_1=3Dx;b_2=3D(a_3=3Dy;b_4=3Dz;a_3<b_4 ? a_3 : b_4);a_1<b_2 ?
a_1 : b_2)"
# -2
local_variables
# ["_", "x", "y", "z", "a_1", "b_2", "a_3", "b_4"]

=20
Not if they don't exist (as I think they don't)

Looks like they do.



=09
__________________________________=20
Yahoo! Mail - PC Magazine Editors' Choice 2005=20
http://mail.yahoo.com
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top