Reusing the name of local variable

  • Thread starter pagerintas pritupimas
  • Start date
P

pagerintas pritupimas

Hi All,

Can someone explain what is the reasoning behind the following behavior?
Local variable "boo" goes out of scope but I am not allowed to reuse the
name. And if it doesn't go out of scope, how come I cannot access its value?

internal sealed class Program
{
private static void Main(string[] args)
{
{
string boo;
}

string foo = boo; // Cannot use local variable 'boo' before it is
declared
string boo; // A local variable named 'boo' cannot be
declared in this scope because it would give a different meaning to 'boo',
which is already used in a 'child' scope to denote something else
}
}
 
J

Jon Skeet [C# MVP]

Can someone explain what is the reasoning behind the following behavior?
Local variable "boo" goes out of scope but I am not allowed to reuse the
name. And if it doesn't go out of scope, how come I cannot access its value?

The reasoning behind forbidding it is that it leads to code which is
hard to read.

The actual scope of a local variable extends up as well as down, but
it's not accessible before its declaration.

Jon
 
A

Alberto Poblacion

pagerintas pritupimas said:
Can someone explain what is the reasoning behind the following behavior?
Local variable "boo" goes out of scope but I am not allowed to reuse the
name. And if it doesn't go out of scope, how come I cannot access its
value?

internal sealed class Program
{
private static void Main(string[] args)
{
{
string boo;
}

string foo = boo; // Cannot use local variable 'boo' before it is
declared
string boo; // A local variable named 'boo' cannot be
declared in this scope because it would give a different meaning to 'boo',
which is already used in a 'child' scope to denote something else
}
}

You can reuse variable names at the same level:
{
string boo;
}
...
{
string boo;
}


But you can't at a nested level:
string boo;
...
{
string boo; //Error here
}

The reasoning being that, in languages where this is allowed (such as
traditional C), this leads to lots of programming mistakes where the
programmer doesn't notice that he is accessing a variable which is not the
intended one.
 
P

pagerintas pritupimas

The reasoning behind forbidding it is that it leads to code which is
hard to read.

Declaring member field and local variable with the same name can also lead
to poor code but compiler doesn't prevent that. And that's fine, because
sometimes I need to do that, to actually make code "more readable". As of
local variables I feel unnecessarily constrained.
The actual scope of a local variable extends up as well as down, but
it's not accessible before its declaration.

Doesn't compiler see that these are two different variables? It could rename
them behind the scene if that's a problem :]
 
P

pagerintas pritupimas

Thanks for the answer. I'm just wondering how putting brackets around a
piece of code makes it more readable :]
 
J

Jon Skeet [C# MVP]

Declaring member field and local variable with the same name can also lead
to poor code but compiler doesn't prevent that. And that's fine, because
sometimes I need to do that, to actually make code "more readable". As of
local variables I feel unnecessarily constrained.

I can't say I've ever been in a situation where it would be a good
course of action. It's easy to work around.
The actual scope of a local variable extends up as well as down, but
it's not accessible before its declaration.

Doesn't compiler see that these are two different variables? It could rename
them behind the scene if that's a problem :]

It considers them to be two different local variables with the same
name, with one of them in the scope of the other. This is not allowed.

Jon
 
P

pagerintas pritupimas

The reasoning behind forbidding it is that it leads to code which is
I can't say I've ever been in a situation where it would be a good
course of action. It's easy to work around.

The point is not that it's hard to work around. It's just that I would like
_myself_ to decide which piece of code is more readable. I believe it could
be implemented as a warning rather than a compile time error as there is no
technological obstacle to compile valid IL code?
 
J

Jon Skeet [C# MVP]

pagerintas pritupimas said:
The point is not that it's hard to work around. It's just that I would like
_myself_ to decide which piece of code is more readable. I believe it could
be implemented as a warning rather than a compile time error as there is no
technological obstacle to compile valid IL code?

Feel free to implement your own compiler for your own language then :)

Seriously, I think this is a very reasonable restriction, and I have no
problems with it being in the language spec. You disagree obviously,
and that's fine - but don't expect it to change any time soon.
 
I

Ignacio Machin \( .NET/ C# MVP \)

Hi,

I do not think that they do create a scope just for that. Most often that is
use in loops or in If statements
 
I

Ignacio Machin \( .NET/ C# MVP \)

Hi,

The point is not that it's hard to work around. It's just that I would
like _myself_ to decide which piece of code is more readable. I believe it
could be implemented as a warning rather than a compile time error as
there is no technological obstacle to compile valid IL code?

This is one of those issues that be discussed without end, The designer
simply decided to do it that way and that is final.
 
S

Scott Roberts

pagerintas pritupimas said:
The point is not that it's hard to work around. It's just that I would
like _myself_ to decide which piece of code is more readable. I believe it
could be implemented as a warning rather than a compile time error as
there is no technological obstacle to compile valid IL code?

While I personally like the fact that the language disallows some naming
conflicts (and wish it did more), I agree that "more readable" is ultimately
up to the programmer. I also agree that there is an apparent inconsistency
in the language's handling of potential naming conflicts. But, as Ignacio
says, it is the way it is - language designer's choice.
 
P

pagerintas pritupimas

Code sample 1:

if (true)
{
string message = string.Format("Message {0}.", 1);
Console.WriteLine(message);
}

string message = string.Format("Message {0}.", 2);
Console.WriteLine(message);

Compiler says: "You can't do that. It would be so hard to read this piece of
code."

Code sample 2:

if (true)
{
string message = string.Format("Message {0}.", 1);
Console.WriteLine(message);
}

{
string message = string.Format("Message {0}.", 2);
Console.WriteLine(message);
}

Compiler says: "It's so much better now, the code is much more readable, go
ahead."

If code readability is the only argument in this situation, then I find it
hardly convincing. Anyway, thanks everybody for taking time to answer :]
 
I

Ian Semmel

Hi,





This is one of those issues that be discussed without end, The designer
simply decided to do it that way and that is final.

There must be another reason. There are zillions of ways to introduce
bugs into a program and introducing a restriction such as this into the
language specification to eliminate just one of them seems a bit weak.

Perhaps it's got something to do with GC or the like. Perhaps they just
made a mistake and decided to change the language spec rather than fix
it (this is a freedom granted to compiler writers that real-world
programmers don't have )
 
J

Jon Skeet [C# MVP]

There must be another reason. There are zillions of ways to introduce
bugs into a program and introducing a restriction such as this into the
language specification to eliminate just one of them seems a bit weak.

Why? There are loads of restrictions in the spec designed to reduce
bugs. Not falling through from one case label to another (when there's
code between them) is one. Not being able to use a local variable which
isn't definitely assigned is another. I could keep going all day ;)
Perhaps it's got something to do with GC or the like. Perhaps they just
made a mistake and decided to change the language spec rather than fix
it (this is a freedom granted to compiler writers that real-world
programmers don't have )

That sounds very unlikely to me.

(And before you envy compiler writers too much, you should think about
the backward compatibility hurdles they have to face. Personally I
think compiler writers - particularly those involved with IDEs as well
- have a very, very tough job. Language designers even more so.)
 
M

Misbah Arefin

--
Misbah Arefin



Jon Skeet said:
Declaring member field and local variable with the same name can also lead
to poor code but compiler doesn't prevent that. And that's fine, because
sometimes I need to do that, to actually make code "more readable". As of
local variables I feel unnecessarily constrained.

I can't say I've ever been in a situation where it would be a good
course of action. It's easy to work around.
The actual scope of a local variable extends up as well as down, but
it's not accessible before its declaration.

Doesn't compiler see that these are two different variables? It could rename
them behind the scene if that's a problem :]

It considers them to be two different local variables with the same
name, with one of them in the scope of the other. This is not allowed.

Its understandable that the compiler thinks of the following code as two
different local variables with the same name with one of them in the scope of
the other

private static void Main(string[] args)
{
string boo;

if(true)
{
string boo; //error here since this is within the scope of the first
declaration
}
}


But given the sample code from pagerintas how is it a child when the outer
variable is declared after the scope block?

private static void Main(string[] args)
{
{
string boo;
}

string boo; // A local variable named 'boo' cannot be declared in
this scope because it would give a different meaning to 'boo', which is
already used in a 'child' scope to denote something else
}

BTW I agree that restricting in this way may to some extent solve possible
misuse of a variable which is not intended but feel that the argument given
that it makes code more readable is unjust... it should be up to the
programmer to decide what is more readable and what is not
 
J

Jon Skeet [C# MVP]

<snip - please don't include text *after* a signature separator. The
whole point of a sig separator is to indicate that everything after it
is a sig>

But given the sample code from pagerintas how is it a child when the outer
variable is declared after the scope block?

private static void Main(string[] args)
{
{
string boo;
}

string boo; // A local variable named 'boo' cannot be declared in
this scope because it would give a different meaning to 'boo', which is
already used in a 'child' scope to denote something else
}

The outer variable isn't declared after the scope block. The scope of
the second boo variable is the whole method body.

From the C# 3 language spec, section 3.7:

<quote>
The scope of a local variable declared in a local-variable-declaration
(§8.5.1) is the block in which the declaration occurs.
</quote>

There's nothing saying it's only from the point of the declaration.
BTW I agree that restricting in this way may to some extent solve possible
misuse of a variable which is not intended but feel that the argument given
that it makes code more readable is unjust... it should be up to the
programmer to decide what is more readable and what is not

That way lies... macros!

Seriously, I don't see that this is a significant restriction, and it
avoids some bugs - therefore I'm in favour of it.
 
I

Ian Semmel

Why? There are loads of restrictions in the spec designed to reduce
bugs. Not falling through from one case label to another (when there's
code between them) is one. Not being able to use a local variable which
isn't definitely assigned is another. I could keep going all day ;)




That sounds very unlikely to me.

(And before you envy compiler writers too much, you should think about
the backward compatibility hurdles they have to face. Personally I
think compiler writers - particularly those involved with IDEs as well
- have a very, very tough job. Language designers even more so.)

But Application designers have the hardest job of all, as they have to
cater for the whims of compiler writers AND users.
 
J

Jon Skeet [C# MVP]

But Application designers have the hardest job of all, as they have to
cater for the whims of compiler writers AND users.

So does the compiler writer though - the application designers *are*
the users.
 
P

Pedro Luna Montalvo

I think this issue is related more to the generated IL, than the readable
of the source code.

Compile the following code, and then inspect the generated IL:

C#:
static void Main()
{
string f = "first text";
{
string i = "inner text";
Console.WriteLine(f);
Console.WriteLine(i);
}
string s = "second text";
Console.WriteLine(f);
Console.WriteLine(s);
}

IL:
..method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 1
.locals init ( <--- here's the declaration for all the local
variables
[0] string f,
[1] string i,
[2] string s)
L_0000: nop
L_0001: ldstr "first text"
L_0006: stloc.0 <--- store the text in the line before, in
the local variable at index 0 ( f )
L_0007: nop
L_0008: ldstr "inner text"
L_000d: stloc.1 <--- store the text in the line before, in the
local variable at index 1 ( i )
L_000e: ldloc.0
L_000f: call void [mscorlib]System.Console::WriteLine(string)
L_0014: nop
L_0015: ldloc.1
L_0016: call void [mscorlib]System.Console::WriteLine(string)
L_001b: nop
L_001c: nop
L_001d: ldstr "second text"
L_0022: stloc.2 <--- store the text in the line before, in the
local variable at index 2 ( s )
L_0023: ldloc.0
L_0024: call void [mscorlib]System.Console::WriteLine(string)
L_0029: nop
L_002a: ldloc.2
L_002b: call void [mscorlib]System.Console::WriteLine(string)
L_0030: nop
L_0031: ret
}

As you see, IL doesn't know about scoped local variables. There's a
declaration block at the start of the method, where all the local variables
are stated. From this point of view, is natural then that the C# compiler
doesn´t admit the following:

{
string s = "x";
}
string s = "y";


But now, what happens when two variables are declared with the same name,
but into different scopes inside the same method??

C#: (watch the local variable i)

static void Main()
{
string f = "first text";
{
string i = "inner text";
Console.WriteLine(f);
Console.WriteLine(i);
}
string s = "second text";
Console.WriteLine(f);
Console.WriteLine(s);
{
string i = "other inner text";
Console.WriteLine(f);
Console.WriteLine(i);
}
}

IL:

..method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 1
.locals init (
[0] string f,
[1] string i, <-- Just declared once!
[2] string s)
L_0000: nop
L_0001: ldstr "first text"
L_0006: stloc.0
L_0007: nop
L_0008: ldstr "inner text"
L_000d: stloc.1 <--- First use of local variable i
L_000e: ldloc.0
L_000f: call void [mscorlib]System.Console::WriteLine(string)
L_0014: nop
L_0015: ldloc.1
L_0016: call void [mscorlib]System.Console::WriteLine(string)
L_001b: nop
L_001c: nop
L_001d: ldstr "second text"
L_0022: stloc.2
L_0023: ldloc.0
L_0024: call void [mscorlib]System.Console::WriteLine(string)
L_0029: nop
L_002a: ldloc.2
L_002b: call void [mscorlib]System.Console::WriteLine(string)
L_0030: nop
L_0031: nop
L_0032: ldstr "other inner text"
L_0037: stloc.1 <-- The compiler re-use the memory allocation!!!
L_0038: ldloc.0
L_0039: call void [mscorlib]System.Console::WriteLine(string)
L_003e: nop
L_003f: ldloc.1
L_0040: call void [mscorlib]System.Console::WriteLine(string)
L_0045: nop
L_0046: nop
L_0047: ret
}


As the local variable i is declared in separated scopes inside the same
method, the compiler "thinks" is safe to re-use the same memory allocation
for both...
This is a little bit clearer to me....

Greetings,
Pedro Luna


pagerintas pritupimas said:
Code sample 1:

if (true)
{
string message = string.Format("Message {0}.", 1);
Console.WriteLine(message);
}

string message = string.Format("Message {0}.", 2);
Console.WriteLine(message);

Compiler says: "You can't do that. It would be so hard to read this piece
of code."

Code sample 2:

if (true)
{
string message = string.Format("Message {0}.", 1);
Console.WriteLine(message);
}

{
string message = string.Format("Message {0}.", 2);
Console.WriteLine(message);
}

Compiler says: "It's so much better now, the code is much more readable,
go ahead."

If code readability is the only argument in this situation, then I find it
hardly convincing. Anyway, thanks everybody for taking time to answer :]
 
J

Jon Skeet [C# MVP]

Pedro Luna Montalvo said:
I think this issue is related more to the generated IL, than the readable
of the source code.

I don't think so. It woud be perfectly possible to generate two
different local variables and do some name munging. After all, it does
that if you have two local variables with the same name and different
types, e.g.

static void Foo()
{
for (int i=0; i < 10; i++)
{
}

{
string i = "hello";
i.ToString();
}
}

If the language designers had chosen to allow this code, the same
techniques could have applied.
 

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

Similar Threads

Possible Compiler Bug (C# 3.0) 10
simple example 14
why do I get compile error 2
Variable vs. child scopes 3
variable scope! 5
Local variables - quick question 9
Overloading or something else? 1
Syntax error 2

Top