¿Por qué no se puede declarar un nombre de variable duplicado en un ámbito local nested?

Basado en esta pregunta reciente, no entiendo la respuesta proporcionada. Parece que deberías ser capaz de hacer algo como esto, ya que sus ámbitos no se superponen

static void Main() { { int i; } int i; } 

Este código no se puede comstackr con el siguiente error:

Una variable local llamada ‘i’ no se puede declarar en este ámbito porque daría un significado diferente a ‘i’, que ya se usa en un scope ‘secundario’ para denotar algo más

No creo que ninguna de las respuestas hasta ahora haya obtenido la línea crucial de la especificación.

De la sección 8.5.1:

El scope de una variable local declarada en una statement de variable local es el bloque en el que se produce la statement . Es un error referirse a una variable local en una posición textual que precede al declarador de variable local de la variable local. Dentro del scope de una variable local, es un error en tiempo de comstackción declarar otra variable local o constante con el mismo nombre.

(Énfasis mío)

En otras palabras, el scope de la variable “posterior” incluye la parte del bloque anterior a la statement, es decir, incluye el bloque “interno” que contiene la variable “anterior”.

No puede hacer referencia a la variable posterior en un lugar anterior a su statement, pero aún está dentro del scope.

“El scope de la variable local o constante se extiende hasta el final del bloque actual. No puede declarar otra variable local con el mismo nombre en el bloque actual o en cualquier bloque nested”. C # 3.0 en una Nutshell, http://www.amazon.com/3-0-Nutshell-Desktop-Reference-OReilly/dp/0596527578/

“El espacio de statement de variable local de un bloque incluye cualquier bloque nested. Por lo tanto, dentro de un bloque nested no es posible declarar una variable local con el mismo nombre que una variable local en un bloque envolvente”. Ámbitos de aplicación variable, MSDN, http://msdn.microsoft.com/en-us/library/aa691107%28v=vs.71%29.aspx

En una nota lateral, esto es todo lo contrario a las reglas de JavaScript y F # scoping.

Desde la especificación del lenguaje C #:

El espacio de statement de variable local de un bloque incluye cualquier bloque nested. Por lo tanto, dentro de un bloque nested no es posible declarar una variable local con el mismo nombre que una variable local en un bloque envolvente.

Esencialmente, no está permitido porque, en C #, sus ámbitos realmente se superponen.

editar: solo para aclarar, el scope de C # se resuelve en el nivel de bloque, no línea por línea. Entonces, si bien es cierto que no puede referirse a una variable en el código que viene antes de su statement, también es cierto que su scope se extiende hasta el comienzo del bloque.

Esta ha sido una regla en C # desde la primera versión.

Permitir ámbitos superpuestos solo generaría confusión (de los progtwigdores, no del comstackdor).

Así que ha sido prohibido a propósito.

No se trata de superposición de ámbitos. En C # un nombre simple no puede significar más de una cosa dentro de un bloque donde se declara. En su ejemplo, el nombre i significa dos cosas diferentes dentro del mismo bloque externo.

En otras palabras, debería poder mover una statement de variable a cualquier lugar dentro del bloque donde se declaró sin hacer que los ámbitos se superpongan. Desde que cambiaste tu ejemplo a:

 static void Main() { int i; { int i; } } 

causaría que los ámbitos de las diferentes variables i solapen, su ejemplo es ilegal.

Para C #, ISO 23270 ( Tecnología de la información – Lenguajes de progtwigción – C # ), §10.3 ( Declaraciones ) dice:

Cada bloque , switch-block , for-statement , foreach-statement o using-statement crea un espacio de statement para variables locales y constantes locales llamado espacio de statement de variable local . Los nombres se introducen en este espacio de statement a través de declaraciones de variables locales y declaraciones de constantes locales .

Si un bloque es el cuerpo de un constructor, método o statement de operador de instancia, o un descriptor de acceso get o set para una statement de indexador, los parámetros declarados en dicha statement son miembros del espacio de statement de variable local del bloque.

Si un bloque es el cuerpo de un método genérico, los parámetros de tipo declarados en dicha statement son miembros del espacio de statement de variable local del bloque.

Es un error que dos miembros de un espacio de statement de variable local tengan el mismo nombre. Es un error que un espacio de statement de variable local y un espacio de statement de variable local nested contengan elementos con el mismo nombre.

[ Nota: por lo tanto, dentro de un bloque nested no es posible declarar una variable local o constante con el mismo nombre que una variable local o constante en un bloque envolvente. Es posible que dos bloques nesteds contengan elementos con el mismo nombre siempre que ninguno de los bloques contenga el otro. nota final ]

Asi que

 public void foobar() { if ( foo() ) { int i = 0 ; ... } if ( bar() ) { int i = 0 ; ... } return ; } 

es legal, pero

 public void foobar() { int i = 0 ; if ( foo() ) { int i = 0 ; ... } ... return ; } 

no es legal Personalmente, creo que la restricción es bastante molesta. Puedo ver emitir una advertencia del comstackdor sobre la superposición del scope, pero ¿un error de comstackción? Demasiado cinturón y tirantes, en mi humilde opinión. Sin embargo, pude ver la virtud de una opción de comstackción y / o pragma (tal vez -pedantic / -practical , #pragma pedantic -practical vs #pragma practical , B^) ).

Acabo de comstackr esto en GCC como C y como C ++. No recibí ningún mensaje de error por lo que parece ser una syntax válida.

Su pregunta está etiquetada como .net y como c. ¿Debería etiquetarse como c #? Ese lenguaje puede tener reglas diferentes que C.

En C, debe poner toda la statement de la variable al comienzo de un bloque. Necesitan llegar todos directamente después de la apertura { antes de cualquier otra statement en este bloque).

Entonces, lo que puedes hacer para que compile es esto:

 static void Main() { { int i; } { int i; } } 

Aquí está su respuesta de MSDN .NET Documentation :

… El espacio de statement de variable local de un bloque incluye cualquier bloque nested. Por lo tanto, dentro de un bloque nested no es posible declarar una variable local con el mismo nombre que una variable local en un bloque envolvente.