¿Por qué los desarrolladores de C # abren los corchetes? [cerrado]

44

He pasado la mayor parte de los últimos años trabajando principalmente con C # y SQL. Todos los programadores con los que trabajé durante ese tiempo tenían la costumbre de colocar la llave de apertura de una función o declaración de flujo de control en una nueva línea. Asi que ...

public void MyFunction(string myArgument)
{
     //do stuff
}

if(myBoolean == true)
{
    //do something
}
else
{
    //do something else
}

Siempre me ha llamado la atención el desperdicio de espacio, especialmente en las declaraciones if / else. Y sé que existen alternativas en versiones posteriores de C #, como:

if(myBoolean == true)
    //do something on one line of code

Pero casi nadie los usó. Todos hicieron lo de rizar-apoyarse-en-nueva línea.

Luego volví a hacer JavaScript después de una larga ausencia. En mi memoria, los desarrolladores de JavaScript solían hacer exactamente lo mismo, pero con todas las nuevas bibliotecas y cosas elegantes, la mayoría de los desarrolladores ponen la llave de apertura después de la declaración:

function MyJavaScriptFunction() {
    //do something
}

Puede ver el sentido en esto, ya que el uso de cierres y punteros de función se ha vuelto popular en JavaScript, ahorra mucho espacio y hace que las cosas sean más legibles. Entonces me pregunté por qué no se veía como lo hecho en C #. De hecho, si prueba la construcción anterior en Visual Studio 2013, en realidad lo reformatea por usted, ¡colocando la llave de apertura en una nueva línea!

Ahora, acabo de ver esta pregunta en Code Review SE: https://codereview.stackexchange.com/questions/48035/questions-responses-let-me-tell-you-about-you En el que aprendí eso en Java, un lenguaje con el que no estoy demasiado familiarizado, se considera de rigor abrir sus llaves justo después de la declaración, en la moda moderna de JavaScript.

Siempre había entendido que C # fue modelado originalmente después de Java, y mantuvo muchos de los mismos estándares de codificación basal. Pero en este caso, parece que no. Entonces supongo que debe haber una buena razón: ¿cuál es la razón? ¿Por qué los desarrolladores de C # (y Visual Studio) aplican la apertura de llaves en una nueva línea?

Bob Tway
fuente
30
La convención es simplemente eso.
Oded
19
Visual Studio no impone nada, el estilo del código es configurable. Algo tiene que ser el predeterminado. El valor predeterminado que es "mejor" es el cambio de bicicletas del orden más alto.
Phoshi
23
El aparato ortopédico al final de la línea es el antiguo estándar K&R C. Kernighan y Ritchie inventaron el lenguaje C cuando las pantallas de la computadora solo tenían 25 líneas (23 si agrega encabezado y líneas de estado). Ese ya no es el caso, ¿verdad? Lo importante es la consistencia en todo el proyecto. No son también los estudios científicos que demuestran que la abrazadera en su propia línea (sangría al mismo nivel que el código, de hecho) mejora código comprensión pesar de lo que la gente piensa que piensan de la estética.
Craig
10
C # siempre ha apoyado la evaluación de una sola línea de código después de un condicional, por cierto. De hecho, eso es lo único que hace, incluso ahora. Poner el código entre llaves después de una expresión de ramificación simplemente convierte esa instrucción en un goto (el compilador crea el alcance utilizando las instrucciones jmp). C ++, Java, C # y JavaScript se basan más o menos en C, con las mismas reglas de análisis subyacentes, en su mayor parte. Entonces, en ese sentido, C # no está "basado en Java".
Craig
10
Como nota al margen, if(myBoolean == true)tiene poco sentido para mí. Mientras estamos en eso, mientras que no if ((myBoolean == true) == true)? Justo if (myBoolean)y eso es suficiente. Lo siento, una mascota mía.
Konrad Morawski

Respuestas:

67

La llave al final de la línea es el antiguo estándar K&R C, del libro de Brian Kernighan y Dennis Ritchie, The C Programming Language , que publicaron en 1978 después de inventar el sistema operativo UNIX y el lenguaje de programación C (creo que C era diseñado principalmente por Ritchie), en AT&T.

Solía ​​haber guerras de llamas sobre "el único estilo verdadero de aparatos ortopédicos".

Ritchie inventó el lenguaje C, y Kernighan escribió el primer tutorial, cuando las pantallas de la computadora solo mostraban unas pocas líneas de texto. De hecho, el desarrollo de UNICS (luego UNIX) comenzó en un DEC PDP-7, que utilizaba una máquina de escribir, una impresora y una cinta de papel para una interfaz de usuario. UNIX y C se terminaron en el PDP-11, con terminales de texto de 24 líneas. Por lo tanto, el espacio vertical era realmente muy importante. Todos tenemos pantallas ligeramente mejores e impresoras de mayor resolución hoy, ¿verdad? Quiero decir, no sé sobre ti, pero tengo tres (3) pantallas de 24 "y 1080p frente a mí en este momento. :-)

Además, gran parte de ese pequeño libro The C Programming Language son ejemplos de código que colocar los corchetes en los extremos de las líneas en lugar de en sus propias líneas supuestamente ahorró una cantidad considerable de dinero en la impresión.

Lo realmente importante es la coherencia en todo un proyecto, o al menos dentro de un archivo de código fuente dado.

También hay estudios científicos que muestran que el aparato ortopédico en su propia línea (de hecho, con sangría al mismo nivel que el código) mejora la comprensión del código a pesar de lo que las personas piensan que piensan de la estética. Le deja muy claro al lector, visual e instintivamente, qué código se ejecuta en qué contexto.

if( true )
    {
    // do some stuff
    }

C # siempre ha apoyado la evaluación de un solo comando después de una expresión de ramificación, por cierto. De hecho, eso es lo único que hace, incluso ahora. Poner el código entre llaves después de una expresión de ramificación solo hace que ese comando sea un goto (el compilador crea el alcance usando las instrucciones jmp). C ++, Java, C # y JavaScript se basan más o menos en C, con las mismas reglas de análisis subyacentes, en su mayor parte. Entonces, en ese sentido, C # no está "basado en Java".

En resumen, este es un tema religioso / de guerra de llamas. Pero hay estudios que dejan bastante claro que organizar el código en bloques mejora la comprensión humana . Al compilador no podría importarle menos. Pero esto también está relacionado con la razón por la que nunca pongo una línea de código después de una rama sin llaves: es demasiado fácil para mí u otro programador colocar otra línea de código allí más tarde y dejar de lado el hecho de que no ejecutar en el mismo contexto con la línea justo antes o después de ella.

EDITAR : solo mire el error de Applegoto fail para obtener un ejemplo perfecto de este problema exacto, que tuvo graves consecuencias en el mundo real.

if( true )
    doSomething();

se convierte en ...

if( true )
    doSomething();
    doSomethingElse();

En este caso, se doSomethingElse()ejecuta cada vez, independientemente del resultado de la prueba, pero debido a que está sangrado al mismo nivel que la doSomething()declaración, es fácil pasarla por alto. Esto no es realmente discutible; Los estudios respaldan esto. Esta es una gran fuente de errores introducidos en el código fuente durante el mantenimiento.

Aún así, admito que la sintaxis de cierre de JavaScript se ve un poco tonta con llaves en sus propias líneas ... estéticamente. :-)

Craig
fuente
13
La parte sobre bloques en condicionales es ligeramente engañosa. En C, el condicional siempre tiene una sola declaración, pero un bloque (también conocido como declaración compuesta) es un tipo de declaración . C # sigue este precedente. De todos modos, la evaluación condicional siempre implica algún tipo de goto condicional o instrucción de ramificación, debido a la naturaleza lineal de todos los conjuntos de instrucciones comunes. Un condicional sin un bloque no es cualitativamente diferente de un condicional con un bloque (excepto en lo que respecta al alcance).
amon
3
@Craig, recuerda, esto fue en Bell Labs, cuando Bell Labs fue contratado para "hacer cosas interesantes" que no necesariamente tenían que ser prácticas para nada. Coloque a las personas inteligentes en un edificio, dígales que hagan una investigación interesante, muévalas de lo que hacen no es "interesante", y, cosa curiosa, las cosas INTERESANTES (como los transistores y Unix) tienden a aparecer. DARPA tenía el mismo enfoque, al principio, y financiaron MUCHO buen trabajo, en nombre de la investigación básica.
John R. Strohm
3
@Craig: en los viejos tiempos de Pascal / Delphi, generalmente lo evitaba para los bloques de una sola línea, ya que Pascal usa beginy enden lugar de llaves, lo que hace que tales errores sean realmente difíciles de omitir, y también es más estricto con respecto a la colocación de punto y coma, pero gastar El año pasado, 4 días de depuración de un problema en C incrustado que se debió a la falta de colocación de llaves ... ¡Creo que debería haber una opción de compilador que haga que las llaves sean obligatorias para las declaraciones de control!
Mark K Cowan
12
Proporcione referencias para "... estudios científicos que demuestren que el aparato ortopédico está en su propia línea ...". Sin al menos dos referencias (de lo contrario, sería estudio , no estudios ), solo se dispara al azar en el aire.
ErikE
2
@ Craig, ¿podría darnos algunas pistas sobre cómo encontrar los estudios de investigación que mencionó?
Grzegorz Adam Kowalski
30

La razón por la que los desarrolladores de C # lo hacen es porque es la configuración predeterminada del formateador automático de Visual Studio. Si bien esta configuración se puede cambiar, la mayoría de las personas no, y por lo tanto, todos los desarrolladores de un equipo tienen que ir con la mayoría.

En cuanto a por qué este es el valor predeterminado en Visual Studio, no lo sé.

Timwi
fuente
15
Es el valor predeterminado en Visual Studio porque era el estilo de codificación generalmente aceptado en Microsoft en el pasado, y de hecho, al menos en algunos equipos de Microsoft, el estilo no era solo llaves en sus propias líneas, sino llaves en sus propias líneas y sangrado Esa también es una opción en Visual Studio (personalmente lo prefiero).
Craig
20
@Craig: Ewwwwwwwww
Lightness
55
@PreferenceBean Hmm. Personalmente, no me gusta el estilo K&R, porque los corchetes simplemente se pierden en el ruido al final de las líneas y el texto me parece desgreñado, lo que no es solo una preferencia estética, sino que tiene un impacto real en la legibilidad / comprensión. Me gusta el espacio en blanco vertical. Era un poco diferente en monitores de 12 "con 24 líneas de texto en los viejos tiempos cuando el espacio vertical era precioso.
Craig
10
@Craig: Esa no es excusa para sangrar las llaves: P
ligereza corre con Mónica
2
@Craig ¿Para hacer miserables a los empleados de Microsoft?
Mateen Ulhaq
18

Como planteé la hipótesis en esta respuesta aquí, https://softwareengineering.stackexchange.com/a/159081/29029 , supongo que la decisión de ir con el refuerzo de Allman podría ser un signo de la herencia de Pascal, dado que Hejlsberg creó a Delphi antes de diseñar C # . Igual que el caso Pascal para nombres de métodos.

Personalmente creo en seguir el adagio "en Roma haz lo que hacen los romanos". Uso Allman's en C #, pero K&R en Java. Estoy tan acostumbrado a eso que cambiar la convención de cualquier manera me molesta.

Creo que cierta diversidad de convenciones es realmente beneficiosa para un desarrollador "multilingüe", ya que ayuda a recordar en qué idioma están codificando en este momento y facilita la diferenciación de varios hábitos. Es un equivalente mental de la memoria muscular, por así decirlo.

Konrad Morawski
fuente
77
+1 para la línea "desarrollador multilenguaje", en realidad. En serio prefiero aparatos ortopédicos en sus propias líneas y sangría. Sin embargo, en el trabajo en, por ejemplo, proyectos ASP.NET (MVC), encuentro que me gusta C # con el estilo "correcto" y JavaScript con el estilo "JavaScript". Eso es un poco irónico, pero, sinceramente, parte de eso es que la sintaxis de cierre de JavaScript es más atractiva con la llave al final de la línea. Así que soy tan esclavo de la estética como cualquier otra persona ...
Craig
PascalCase para nombres de métodos era un estándar en Microsoft mucho antes de que Anders Hejlsberg dejara Borland para ser un ingeniero de software distinguido en Microsoft.
Craig
2
Curiosamente, uso Allman para todos los idiomas de bloque de llaves. Sin embargo, estoy cada vez más interesado en cómo se vería en Java una conversión de sangría previa al procesamiento en bloques de llaves. El código "java" podría verse extremadamente limpio, una vez que envolví mi mente de reconocimiento de patrones. Creo que Python podría tener razón: no hay una gran razón para usar llaves en un idioma.
tgm1024
Usar espacios en blanco para controlar el flujo del programa es una locura. Python es popular en estos días, pero este aspecto de Python ha sido un poco loco desde que apareció por primera vez.
Craig
Fan de @Craig Python aquí, tratando de hacer algo en javascript. Mirando su otra respuesta y su edición sobre el goto failuso de la sangría para controlar el flujo del programa es lo que los humanos naturalmente quieren hacer, así que lo que ve es lo que se ejecuta. Si está indentado mal, simplemente no funciona. Tener que decodificar lo que significan esas llaves, si realmente reflejan la sangría, es un trabajo adicional además de comprender el programa. La sangría es redundante para las llaves, entonces, ¿por qué los programadores la usan si las llaves son útiles? La anidación profunda es ininteligible en cualquier idioma. Jus 'sayin'.
Neil_UK
14

La convención que asocias con Java es el estilo K&R, o el "Estilo de una llave verdadera", y originalmente proviene de C. Esta página con sangría del venerable Archivo Jargon muestra la antigüedad de la distinción.

Siempre he pensado que el estilo de Allman y sus variantes son un reflejo de cómo piensan los autores sobre el código, elevando los delimitadores de bloque al nivel de palabras clave similares a cómo algunos idiomas usan "comenzar" y "terminar" alrededor de bloques de código.

John Bickers
fuente
Tengo la impresión de que en estos días OTBS (un verdadero estilo de llave) también implica nunca dejar las llaves después de las declaraciones de control, incluso para líneas de código individuales. Ver el error de error de Goto de Apple.
Craig