Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > ideas for an RCR: variable locality

Reply
Thread Tools

ideas for an RCR: variable locality

 
 
Eric Mahurin
Guest
Posts: n/a
 
      10-01-2005
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


 
Reply With Quote
 
 
 
 
Trans
Guest
Posts: n/a
 
      10-01-2005
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
]

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

T.

 
Reply With Quote
 
 
 
 
Linus Sellberg
Guest
Posts: n/a
 
      10-01-2005
------=_Part_6637_26146152.1128192797250
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

On 10/1/05, Trans <> wrote:
>
> z =3D lambda [
> share
> ]



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--


 
Reply With Quote
 
Bob Hutchison
Guest
Posts: n/a
 
      10-01-2005

On Oct 1, 2005, at 12:20 PM, Eric Mahurin wrote:


> 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



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


----
Bob Hutchison -- blogs at <http://www.recursive.ca/hutch/>
Recursive Design Inc. -- <http://www.recursive.ca/>
Raconteur -- <http://www.raconteur.info/>





 
Reply With Quote
 
Eric Mahurin
Guest
Posts: n/a
 
      10-01-2005
--- Trans <> wrote:

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


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


 
Reply With Quote
 
ES
Guest
Posts: n/a
 
      10-01-2005
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).

> [snip solutions]


E
--
No-one expects the Solaris POSIX implementation!


 
Reply With Quote
 
Trans
Guest
Posts: n/a
 
      10-01-2005

Eric Mahurin wrote:
> --- Trans <> wrote:
>
> > And a way to share vars from the above scope specifically:
> >
> > z = lambda [
> > share
> > ]

>
> 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.

 
Reply With Quote
 
Eric Mahurin
Guest
Posts: n/a
 
      10-01-2005
--- ES <ruby-> wrote:

> 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).
> >=20
> > 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.
> >=20
> > 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.
>=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


 
Reply With Quote
 
Bob Hutchison
Guest
Posts: n/a
 
      10-01-2005

On Oct 1, 2005, at 4:55 PM, Eric Mahurin wrote:


> --- ES <ruby-> wrote:
>
>
>
>> 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.
>
>


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)

----
Bob Hutchison -- blogs at <http://www.recursive.ca/hutch/>
Recursive Design Inc. -- <http://www.recursive.ca/>
Raconteur -- <http://www.raconteur.info/>





 
Reply With Quote
 
ES
Guest
Posts: n/a
 
      10-01-2005
Eric Mahurin wrote:
> --- ES <ruby-> wrote:
>
>
>>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.

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



 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: [Python-ideas] string.format() default variable assignment Chris Angelico Python 27 03-05-2013 11:35 AM
"Variable variable name" or "variable lvalue" mfglinux Python 11 09-12-2007 03:08 AM
video buffering scheme, nonsequential access (no spatial locality) wallge VHDL 14 01-30-2007 04:07 PM
multidimensional scaling and locality preserving projection paolo.marocco@fastwebnet.it Java 0 12-04-2005 12:19 PM
How do I scope a variable if the variable name contains a variable? David Filmer Perl Misc 19 05-21-2004 03:55 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57