duplicated local variables with same name

classic Classic list List threaded Threaded
22 messages Options
12
Reply | Threaded
Open this post in threaded view
|

duplicated local variables with same name

Jinhua Luo
Hi All,

The reference says "Notice that each execution of a local statement defines new local variables", however, does it make sense to statements with the same variable name?
Even the lua parser creates new variables, only the last one is visible.
For example,

local val = 1
local val = 1
local val = 1
print(val)

The output from luac is:
0+ params, 5 slots, 1 upvalue, 3 locals, 2 constants, 0 functions
    1    [1]    LOADK        0 -1    ; 1
    2    [2]    LOADK        1 -1    ; 1
    3    [3]    LOADK        2 -1    ; 1
    4    [4]    GETTABUP     3 0 -2    ; _ENV "print"
    5    [4]    MOVE         4 2
    6    [4]    CALL         3 2 1
    7    [4]    RETURN       0 1
The print only sees the last one, while the first two are useless.
So why the parser do not recognize this case and keep only one variable instance? Is there some special consideration?


Regards,
Jinhua Luo
Reply | Threaded
Open this post in threaded view
|

Re: duplicated local variables with same name

Luiz Henrique de Figueiredo
> So why the parser do not recognize this case and keep only one variable instance?

For all pratical purposes, it does not matter: the program will have the
same behavior regardless.

So, why complicate the parser?

Reply | Threaded
Open this post in threaded view
|

Re: duplicated local variables with same name

Rena
In reply to this post by Jinhua Luo
On Mon, Jun 15, 2015 at 8:44 AM, Jinhua Luo <[hidden email]> wrote:

> Hi All,
>
> The reference says "Notice that each execution of a local statement defines
> new local variables", however, does it make sense to statements with the
> same variable name?
> Even the lua parser creates new variables, only the last one is visible.
> For example,
>
> local val = 1
> local val = 1
> local val = 1
> print(val)
>
> The output from luac is:
> 0+ params, 5 slots, 1 upvalue, 3 locals, 2 constants, 0 functions
>     1    [1]    LOADK        0 -1    ; 1
>     2    [2]    LOADK        1 -1    ; 1
>     3    [3]    LOADK        2 -1    ; 1
>     4    [4]    GETTABUP     3 0 -2    ; _ENV "print"
>     5    [4]    MOVE         4 2
>     6    [4]    CALL         3 2 1
>     7    [4]    RETURN       0 1
> The print only sees the last one, while the first two are useless.
> So why the parser do not recognize this case and keep only one variable
> instance? Is there some special consideration?
>
>
> Regards,
> Jinhua Luo

It does if you have more code:

local x, y = getPosition()
render(x, y)
--...
local x, y = getSpeed()
doOtherThingsWith(x, y)

It's even more important if you create a closure in between those definitions.

--
Sent from my Game Boy.

Reply | Threaded
Open this post in threaded view
|

Re: duplicated local variables with same name

Jinhua Luo
In reply to this post by Luiz Henrique de Figueiredo
Maybe the reference should describe more: "local" should be used once to declare new local variable (with different variable name).
After all, the max number of local variables is limited due to the opcode format.

2015-06-15 21:03 GMT+08:00 Luiz Henrique de Figueiredo <[hidden email]>:
> So why the parser do not recognize this case and keep only one variable instance?

For all pratical purposes, it does not matter: the program will have the
same behavior regardless.

So, why complicate the parser?


Reply | Threaded
Open this post in threaded view
|

Re: duplicated local variables with same name

KHMan
On 6/15/2015 9:26 PM, Jinhua Luo wrote:
> Maybe the reference should describe more: "local" should be used
> once to declare new local variable (with different variable name).
> After all, the max number of local variables is limited due to the
> opcode format.

It's an interpreted implementation of a programming language.
There are bits of 'inefficiencies' here and there, but the effects
are minimal. A trade-off, if you will -- clarity versus complexity.

If one writes benchmarks, of course it's possible to maximize
minor things. But most users would be writing sane code and will
do fine.

That said, there are plenty of optimizations that can be
implemented. Then you'd need a lot of new debug info and code...
Anyone know of any [interpreter] implementations that focuses on
optimizations? (Apart from the usual JIT suspects like LuaJIT and
Ravi, that is.)

> 2015-06-15 21:03 GMT+08:00 Luiz Henrique de Figueiredo:
>
>     > So why the parser do not recognize this case and keep only one variable instance?
>
>     For all pratical purposes, it does not matter: the program
>     will have the
>     same behavior regardless.
>
>     So, why complicate the parser?

--
Cheers,
Kein-Hong Man (esq.)
Kuala Lumpur, Malaysia


Reply | Threaded
Open this post in threaded view
|

Re: duplicated local variables with same name

Dirk Laurie-2
In reply to this post by Jinhua Luo
2015-06-15 15:26 GMT+02:00 Jinhua Luo <[hidden email]>:

> Maybe the reference should describe more: "local" should be used
> once to declare new local variable (with different variable name).
> After all, the max number of local variables is limited due to the opcode
> format.

The manual says in §3.5:

    Notice that each execution of a local statement defines new local
    variables.

That implies that the code

local val = 1
local val = 1
local val = 1

will three times create a local variable called "val" and initialize it
to 1. This may be a silly, sloppy and stupid thing to do but it is not
illegal, and as "Rena" has pointed out, it is possible to write code
in which reusing the name is the intended behaviour.

As in many other places, the manual here says clearly and
unambiguously what it means, albeit with implications that might
be missed at first reading by a hasty reader.

Reply | Threaded
Open this post in threaded view
|

Re: duplicated local variables with same name

Patrick Donnelly
On Mon, Jun 15, 2015 at 11:16 AM, Dirk Laurie <[hidden email]> wrote:

> 2015-06-15 15:26 GMT+02:00 Jinhua Luo <[hidden email]>:
>
>> Maybe the reference should describe more: "local" should be used
>> once to declare new local variable (with different variable name).
>> After all, the max number of local variables is limited due to the opcode
>> format.
>
> The manual says in §3.5:
>
>     Notice that each execution of a local statement defines new local
>     variables.
>
> That implies that the code
>
> local val = 1
> local val = 1
> local val = 1
>
> will three times create a local variable called "val" and initialize it
> to 1. This may be a silly, sloppy and stupid thing to do but it is not
> illegal, and as "Rena" has pointed out, it is possible to write code
> in which reusing the name is the intended behaviour.

The correct idiom (but not really) is to do this:

do
  local x, y = ...
end

do
  local x, y = ...
end

That reuses the registers for x and y so you could repeat those blocks
forever without problems.

[It's a shame that declaring blocks that limit temporary variable
scope isn't more popular, perhaps the extra two lines and bonus
character in 'end' bothers OCD people like myself. I'm a fan of using
{} in C code but I admit it always looks weird.]

--
Patrick Donnelly

Reply | Threaded
Open this post in threaded view
|

Re: duplicated local variables with same name

Roberto Ierusalimschy
> [It's a shame that declaring blocks that limit temporary variable
> scope isn't more popular, perhaps the extra two lines and bonus
> character in 'end' bothers OCD people like myself. I'm a fan of using
> {} in C code but I admit it always looks weird.]

For me the problem is not the extra two lines, but the need to ident the
code inside the block. (Of course, for those that are not OCD, there is
always the option of not identing that code...)

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: duplicated local variables with same name

Rena
On Mon, Jun 15, 2015 at 1:13 PM, Roberto Ierusalimschy
<[hidden email]> wrote:

>> [It's a shame that declaring blocks that limit temporary variable
>> scope isn't more popular, perhaps the extra two lines and bonus
>> character in 'end' bothers OCD people like myself. I'm a fan of using
>> {} in C code but I admit it always looks weird.]
>
> For me the problem is not the extra two lines, but the need to ident the
> code inside the block. (Of course, for those that are not OCD, there is
> always the option of not identing that code...)
>
> -- Roberto
>

You don't need OCD to appreciate the benefits of well-structured,
well-organized code and make it a rule for yourself to follow
formatting guidelines.

--
Sent from my Game Boy.

Reply | Threaded
Open this post in threaded view
|

Re: duplicated local variables with same name

Sven Olsen
In reply to this post by Patrick Donnelly
[It's a shame that declaring blocks that limit temporary variable
scope isn't more popular, perhaps the extra two lines and bonus
character in 'end' bothers OCD people like myself.

I've started writing do-blocks structured like the following:

  local draw_list do

    <other locals and definitions>

    draw_list= function() 
      <drawing code> 
    end
  end

The convention here is that the do block acts more or less like a 1 time function call who's purpose is to define the local(s) on the line where it starts. Feels like a useful pattern when I have a bunch of function definitions that all want their own copies of common variable names like 'x','y' etc.

-Sven



Reply | Threaded
Open this post in threaded view
|

Re: duplicated local variables with same name

Sean Conner
In reply to this post by Roberto Ierusalimschy
It was thus said that the Great Roberto Ierusalimschy once stated:
> > [It's a shame that declaring blocks that limit temporary variable
> > scope isn't more popular, perhaps the extra two lines and bonus
> > character in 'end' bothers OCD people like myself. I'm a fan of using
> > {} in C code but I admit it always looks weird.]
>
> For me the problem is not the extra two lines, but the need to ident the
> code inside the block. (Of course, for those that are not OCD, there is
> always the option of not identing that code...)

  I can just highlight the code in my editor and shift the text as needed
(left or right---and my editor respects my preferred indent level).

  -spc


Reply | Threaded
Open this post in threaded view
|

Re: duplicated local variables with same name

Soni "They/Them" L.
In reply to this post by Sven Olsen


On 15/06/15 03:16 PM, Sven Olsen wrote:
[It's a shame that declaring blocks that limit temporary variable
scope isn't more popular, perhaps the extra two lines and bonus
character in 'end' bothers OCD people like myself.

I've started writing do-blocks structured like the following:

  local draw_list do

    <other locals and definitions>

    draw_list= function() 
      <drawing code> 
    end
  end

The convention here is that the do block acts more or less like a 1 time function call who's purpose is to define the local(s) on the line where it starts. Feels like a useful pattern when I have a bunch of function definitions that all want their own copies of common variable names like 'x','y' etc.

-Sven



Bad on LuaJIT. If you're gonna do that I recommend you use (function(...) end)(...), e.g.

local draw_list = (function(...)
  <stuff>
  return function(list)
    <drawing code>
  end
end)(...) -- pass our chunk's vargs to the function

This lets LuaJIT know draw_list is a constant and make your code faster. (direct jump vs indirect jump)
-- 
Disclaimer: these emails are public and can be accessed from <TODO: get a non-DHCP IP and put it here>. If you do not agree with this, DO NOT REPLY.
Reply | Threaded
Open this post in threaded view
|

Re: duplicated local variables with same name

Brigham Toskin
On Mon, Jun 15, 2015 at 12:35 PM, Soni L. <[hidden email]> wrote:


On 15/06/15 03:16 PM, Sven Olsen wrote:
[It's a shame that declaring blocks that limit temporary variable
scope isn't more popular, perhaps the extra two lines and bonus
character in 'end' bothers OCD people like myself.

I've started writing do-blocks structured like the following:

  local draw_list do

    <other locals and definitions>

    draw_list= function() 
      <drawing code> 
    end
  end

The convention here is that the do block acts more or less like a 1 time function call who's purpose is to define the local(s) on the line where it starts. Feels like a useful pattern when I have a bunch of function definitions that all want their own copies of common variable names like 'x','y' etc.

-Sven
Bad on LuaJIT. If you're gonna do that I recommend you use (function(...) end)(...), e.g.

local draw_list = (function(...)
  <stuff>
  return function(list)
    <drawing code>
  end
end)(...) -- pass our chunk's vargs to the function

This lets LuaJIT know draw_list is a constant and make your code faster. (direct jump vs indirect jump)

I'm curious if you've actually dumped the traces to see this difference, or if you're assuming it will do this based on documentation or some other thread on the subject?

--
Brigham Toskin
Reply | Threaded
Open this post in threaded view
|

Re: duplicated local variables with same name

Soni "They/Them" L.


On 16/06/15 05:42 PM, Brigham Toskin wrote:
On Mon, Jun 15, 2015 at 12:35 PM, Soni L. <[hidden email]> wrote:


On 15/06/15 03:16 PM, Sven Olsen wrote:
[It's a shame that declaring blocks that limit temporary variable
scope isn't more popular, perhaps the extra two lines and bonus
character in 'end' bothers OCD people like myself.

I've started writing do-blocks structured like the following:

  local draw_list do

    <other locals and definitions>

    draw_list= function() 
      <drawing code> 
    end
  end

The convention here is that the do block acts more or less like a 1 time function call who's purpose is to define the local(s) on the line where it starts. Feels like a useful pattern when I have a bunch of function definitions that all want their own copies of common variable names like 'x','y' etc.

-Sven
Bad on LuaJIT. If you're gonna do that I recommend you use (function(...) end)(...), e.g.

local draw_list = (function(...)
  <stuff>
  return function(list)
    <drawing code>
  end
end)(...) -- pass our chunk's vargs to the function

This lets LuaJIT know draw_list is a constant and make your code faster. (direct jump vs indirect jump)

I'm curious if you've actually dumped the traces to see this difference, or if you're assuming it will do this based on documentation or some other thread on the subject?
I'm assuming based on documentation/other thread, and also this: the opcodes indicate "local x do x = function() end end" loads "nil" into x, then changes x later, so LuaJIT can't just assume "x" is constant/immutable so instead it uses an indirect jump when you call x. with "local x = (function(...) return function() end end)(...)" there's a call opcode but x doesn't get implicitly nil-ed before it.

--
Brigham Toskin

-- 
Disclaimer: these emails are public and can be accessed from <TODO: get a non-DHCP IP and put it here>. If you do not agree with this, DO NOT REPLY.
Reply | Threaded
Open this post in threaded view
|

Re: duplicated local variables with same name

Brigham Toskin
On Tue, Jun 16, 2015 at 1:53 PM, Soni L. <[hidden email]> wrote:
On 16/06/15 05:42 PM, Brigham Toskin wrote:
I'm curious if you've actually dumped the traces to see this difference, or if you're assuming it will do this based on documentation or some other thread on the subject?
I'm assuming based on documentation/other thread, and also this: the opcodes indicate "local x do x = function() end end" loads "nil" into x, then changes x later, so LuaJIT can't just assume "x" is constant/immutable so instead it uses an indirect jump when you call x. with "local x = (function(...) return function() end end)(...)" there's a call opcode but x doesn't get implicitly nil-ed before it.

This seems like exactly the kind of situation the tracing compiler might excel at optimizing "properly". Though that argument's moot if in fact it doesn't. Might be worth checking out, for those people that use blocks like this a lot.

--
Brigham Toskin
Reply | Threaded
Open this post in threaded view
|

Re: duplicated local variables with same name

Robert Virding-2
When I first implement luerl, Lua in erlang, I didn't realise this and just overwrote the variables. But eventually I read the manual a bit more closely and got it right. I find personally find it both logical and illogical, coming from other languages I would expect the compiler to complain.

Robert


On 16 June 2015 at 23:24, Brigham Toskin <[hidden email]> wrote:
On Tue, Jun 16, 2015 at 1:53 PM, Soni L. <[hidden email]> wrote:
On 16/06/15 05:42 PM, Brigham Toskin wrote:
I'm curious if you've actually dumped the traces to see this difference, or if you're assuming it will do this based on documentation or some other thread on the subject?
I'm assuming based on documentation/other thread, and also this: the opcodes indicate "local x do x = function() end end" loads "nil" into x, then changes x later, so LuaJIT can't just assume "x" is constant/immutable so instead it uses an indirect jump when you call x. with "local x = (function(...) return function() end end)(...)" there's a call opcode but x doesn't get implicitly nil-ed before it.

This seems like exactly the kind of situation the tracing compiler might excel at optimizing "properly". Though that argument's moot if in fact it doesn't. Might be worth checking out, for those people that use blocks like this a lot.

--
Brigham Toskin

Reply | Threaded
Open this post in threaded view
|

Re: duplicated local variables with same name

Rena
On Wed, Jun 17, 2015 at 5:21 PM, Robert Virding <[hidden email]> wrote:

> When I first implement luerl, Lua in erlang, I didn't realise this and just
> overwrote the variables. But eventually I read the manual a bit more closely
> and got it right. I find personally find it both logical and illogical,
> coming from other languages I would expect the compiler to complain.
>
> Robert
>
>
> On 16 June 2015 at 23:24, Brigham Toskin <[hidden email]> wrote:
>>
>> On Tue, Jun 16, 2015 at 1:53 PM, Soni L. <[hidden email]> wrote:
>>>
>>> On 16/06/15 05:42 PM, Brigham Toskin wrote:
>>>
>>> I'm curious if you've actually dumped the traces to see this difference,
>>> or if you're assuming it will do this based on documentation or some other
>>> thread on the subject?
>>>
>>> I'm assuming based on documentation/other thread, and also this: the
>>> opcodes indicate "local x do x = function() end end" loads "nil" into x,
>>> then changes x later, so LuaJIT can't just assume "x" is constant/immutable
>>> so instead it uses an indirect jump when you call x. with "local x =
>>> (function(...) return function() end end)(...)" there's a call opcode but x
>>> doesn't get implicitly nil-ed before it.
>>
>>
>> This seems like exactly the kind of situation the tracing compiler might
>> excel at optimizing "properly". Though that argument's moot if in fact it
>> doesn't. Might be worth checking out, for those people that use blocks like
>> this a lot.
>>
>> --
>> Brigham Toskin
>
>

It has bit me a few times:

local min, max = math.min, math.max
[...]
function frobulate(obj)
    local size, rate, max = obj.size, obj.rate, obj.max
    [...]
    x = max(size, config.min_size)
end

--
Sent from my Game Boy.

Reply | Threaded
Open this post in threaded view
|

Re: duplicated local variables with same name

Brigham Toskin
In reply to this post by Robert Virding-2
On Wed, Jun 17, 2015 at 2:21 PM, Robert Virding <[hidden email]> wrote:
When I first implement luerl, Lua in erlang, I didn't realise this and just overwrote the variables. But eventually I read the manual a bit more closely and got it right. I find personally find it both logical and illogical, coming from other languages I would expect the compiler to complain.

Well, consider the following C program:

    #include <stdio.h>

    int main(void)
    {
      int foo = 25;
      {
     int foo = 100;
     printf("foo == %d\n", foo);
      }
      printf("foo == %d\n", foo);

      return 0;
    }

Would you expect an error? Perhaps you don't actually know C, if you're steeped in awesome things like Lua and Erlang, but this totally valid C. In fact, it outputs what you would expect, if you were familiar with Lua local scoping with blocks:

    foo == 100
    foo == 25

You can't redefine a var in the same scope like you can with Lua or say Go's := operator, but you can definitely redefine variables within a scope in lots of languages.
--
Brigham Toskin
Reply | Threaded
Open this post in threaded view
|

Re: duplicated local variables with same name

Tim Hill

On Jun 17, 2015, at 4:07 PM, Brigham Toskin <[hidden email]> wrote:

Would you expect an error? Perhaps you don't actually know C, if you're steeped in awesome things like Lua and Erlang, but this totally valid C. In fact, it outputs what you would expect, if you were familiar with Lua local scoping with blocks:

    foo == 100
    foo == 25

You can't redefine a var in the same scope like you can with Lua or say Go's := operator, but you can definitely redefine variables within a scope in lots of languages.


But I think that’s not the point. In C what you CANNOT do is:

int foo = 25;
int foo = 25;

.. but you CAN do something similar to this in Lua.

—Tim


Reply | Threaded
Open this post in threaded view
|

Re: duplicated local variables with same name

Brigham Toskin
Yeah, that's why I mentioned Go. you can do

foo := 25
foo := "I'm a foo!"
foo = 25 // ERROR! foo is type string!

On Wed, Jun 17, 2015 at 6:48 PM, Tim Hill <[hidden email]> wrote:

On Jun 17, 2015, at 4:07 PM, Brigham Toskin <[hidden email]> wrote:

Would you expect an error? Perhaps you don't actually know C, if you're steeped in awesome things like Lua and Erlang, but this totally valid C. In fact, it outputs what you would expect, if you were familiar with Lua local scoping with blocks:

    foo == 100
    foo == 25

You can't redefine a var in the same scope like you can with Lua or say Go's := operator, but you can definitely redefine variables within a scope in lots of languages.


But I think that’s not the point. In C what you CANNOT do is:

int foo = 25;
int foo = 25;

.. but you CAN do something similar to this in Lua.

—Tim





--
Brigham Toskin
12