¿Algún otro idioma que no sea JavaScript tiene una diferencia entre las ubicaciones de inicio de las llaves (la misma línea y la siguiente)?

91

Hoy, mientras leía al azar el libro de patrones de JavaScript O'Reilly, encontré algo interesante (página 27 como referencia).

En Javascript, en algunos casos, hay una diferencia si la ubicación de inicio de la riostra es diferente.

function test_function1() {
    return
    {
        name: 'rajat'
    };
}

var obj = test_function1();
alert(obj);  //Shows "undefined"

Mientras

function test_function2() {
    return {
        name: 'rajat'
    };
}

var obj = test_function2();
alert(obj); //Shows object

Demostración de JSfiddle

¿Hay algún otro idioma que tenga ese comportamiento? Si es así, seguro que tendría que cambiar mi hábito .. :)

Me preocupa principalmente PHP, C, C ++, Java y ruby.

Rajat Singhal
fuente
1
Reproducido en Chrome e IE9, buena captura: P
gideon
4
Se puede hacer que la sensibilidad del espacio en blanco funcione --- mire Python o el modo de línea fortran --- pero la sensibilidad sutil del espacio en blanco es obra del diablo. ¡Gah! ¡Esto es tan malo como hacer!
dmckee --- ex-moderador gatito
¡Esto es impresionante! ¡Buen hallazgo!
CheckRaise
Ahora quiero saber por qué JavaScript se comporta de esta manera.
CheckRaise
4
@CheckRaise: resumo las reglas aquí: blogs.msdn.com/b/ericlippert/archive/2004/02/02/…
Eric Lippert

Respuestas:

53

Cualquier lenguaje que no se base en punto y coma (sino en líneas nuevas) para delimitar declaraciones potencialmente permite esto. Considere Python :

>>> def foo():
...   return
...   { 1: 2 }
... 
>>> def bar():
...   return { 1: 2 }
... 
>>> foo()
>>> bar()
{1: 2}

Es posible que pueda construir un caso similar en Visual Basic, pero en la parte superior de mi cabeza no puedo entender cómo porque VB es bastante restrictivo en el lugar donde se pueden colocar los valores. Pero lo siguiente debería funcionar, a menos que el analizador estático se queje de un código inalcanzable:

Try
    Throw New Exception()
Catch ex As Exception
    Throw ex.GetBaseException()
End Try

' versus

Try
    Throw New Exception()
Catch ex As Exception
    Throw
    ex.GetBaseException()
End Try

De los idiomas que mencionaste, Ruby tiene la misma propiedad. PHP, C, C ++ y Java no lo hacen simplemente porque descartan la nueva línea como espacios en blanco y requieren punto y coma para delimitar las declaraciones.

Aquí está el código equivalente del ejemplo de Python en Ruby:

>> def foo
>>   return { 1 => 2 }
>> end
=> nil
>> def bar
>>   return
>>   { 1 => 2 }
>> end
=> nil
>> foo
=> {1=>2}
>> bar
=> nil
Konrad Rudolph
fuente
2
Su ejemplo de VB no lo hace bien porque VB nunca permite que una declaración abarque varias líneas a menos que use la secuencia de continuación de línea "_".
phoog
2
Ok, me retracto del comentario anterior porque acabo de ver la especificación, hay algunos contextos en los que VB.NET admite continuaciones de línea implícitas. Sin embargo, dudo que cualquier programador experimentado de VB considere este ejemplo como un "error", ya que es bastante obvio que Throwy ex.GetBaseException()son líneas lógicas separadas. Más específicamente, dado que Basic históricamente usa líneas para delimitar sus declaraciones, es más probable que un "gotcha" sea una situación en la que un programador cree que ha creado una nueva declaración en una nueva línea lógica, pero no lo ha hecho.
phoog
@phoog Es cierto, absolutamente no es un problema.
Konrad Rudolph
40

El intérprete de JavaScript agrega automáticamente un ;al final de cada línea si no encuentra uno (con algunas excepciones, no los ingresa aquí :).

Básicamente, el problema no es la ubicación de las llaves (que aquí representan un objeto literal, no un bloque de código como en la mayoría de los lenguajes), sino esta pequeña "característica" que obliga a su primer ejemplo a return ;=> undefined. Puede consultar el comportamiento de return en la especificación ES5 .

Para otros idiomas que tienen un comportamiento similar, consulte la respuesta de Konrad .

Alex Ciminian
fuente
5
Respuesta muy votada, pero en realidad está mal, lo siento. La explicación es buena, pero corrija el error.
Konrad Rudolph
La parte sobre JavaScript no está mal, la forma en que se comporta como lo hace es debido a la inserción de punto y coma que obliga undefineda ser devuelto. Escribí un poco sobre los otros idiomas con el prefijo afaik , así que tómatelo con un grano de sal :).
Alex Ciminian
5
Pero no es cierto que JS inserte un punto y coma "al final de cada línea" "con algunas excepciones"; más bien, por lo general no inserta un punto y coma, y ​​solo hay algunos casos en los que lo hace . Por eso causa tantos errores.
ruakh
26

Seguramente. El lenguaje de programación go de Google exhibe un comportamiento muy similar (aunque con diferentes efectos). Como se explica allí:

De hecho, lo que sucede es que el lenguaje formal usa punto y coma, como en C o Java, pero se insertan automáticamente al final de cada línea que parece el final de una declaración. No es necesario que los escriba usted mismo.

..recorte...

Este enfoque permite obtener un código limpio y sin punto y coma. La única sorpresa es que es importante colocar la llave de apertura de una construcción como una declaración if en la misma línea que la if; si no lo hace, hay situaciones que pueden no compilarse o pueden dar un resultado incorrecto. El lenguaje fuerza el estilo de corsé hasta cierto punto.

En secreto, creo que Rob Pike solo quería una excusa para requerir el One True Brace Style.

Dave
fuente
10
Genial, no sabía nada de esto :). Personalmente, no creo que la inserción automática de punto y coma sea una buena idea. Puede introducir errores sutiles que las personas sin experiencia con el idioma tendrán dificultades para descifrar. Si desea escribir código sin punto y coma, prefiero la forma de Python.
Alex Ciminian
Incluso los idiomas @Alex sin ningún punto y coma (VB) tienen esta propiedad. Y también lo hace Python, que aparentemente prefiere, a pesar de que maneja esto de manera idéntica a JavaScript.
Konrad Rudolph
Votaría a favor, excepto que tu segunda oración es tan completamente incorrecta que me dan ganas de votar en contra. Supongo que se cancelan. ;-)
ruakh
1
@ruakh, ¿te refieres a "ir hace exactamente esto" o te refieres a la broma sobre rob pike? En el primer caso, podría reformularlo para "ir exhibe el mismo comportamiento", en el segundo, lo siento si mi pobre sentido del humor ofende;)
Dave
1
Me refiero a que "Go hace exactamente esto". La propuesta original para la inserción de punto y coma de Go se contrasta explícitamente con la de JavaScript, explicando: "Esta propuesta puede recordarle la regla de punto y coma opcional de JavaScript, que en efecto agrega punto y coma para corregir errores de análisis. La propuesta de Go es profundamente diferente", y eso es bastante cierto, en todos los niveles: funciona de manera diferente, tiene diferentes efectos y casi no tiene trampas. (OTBS y judiciales, mientras molesto, no es un gotcha, ya que es un requisito consistente en todo el código Go.)
ruakh
14

La respuesta a esa pregunta es bastante sencilla. Cualquier idioma que tenga "inserción automática de punto y coma" podría tener problemas en esa línea. El problema con esto

return
{
     name: 'rajat'
};

..es que el motor js insertará un punto y coma después de la return;declaración (y por lo tanto, regresará undefined). Este ejemplo es una buena razón para abrir las llaves siempre en el lado derecho y nunca también en el lado izquierdo. Como ya lo notó correctamente, si hay un corchete en la misma línea, el interpretador lo notará y no podrá insertar un punto y coma.

jAndy
fuente
6

FWIW, JSLint informa varias advertencias con esa sintaxis:

$ jslint -stdin
function foo(){
  return
  { x: "y" };
}
^D
(3): lint warning: unexpected end of line; it is ambiguous whether these lines are part of the same statement
  return
........^

(3): lint warning: missing semicolon
  { x: "y" };
..^

(3): lint warning: unreachable code
  { x: "y" };
..^

(3): lint warning: meaningless block; curly braces have no impact
  { x: "y" };
..^

(3): lint warning: use of label
  { x: "y" };
.....^

(3): lint warning: missing semicolon
  { x: "y" };
...........^

(3): lint warning: empty statement or extra semicolon
  { x: "y" };
............^


0 error(s), 7 warning(s)
Brandan
fuente
1

El primer idioma en el que encontré esto fue awk (que también tiene su parte de "rarezas" de sintaxis; punto y coma opcionales, concatenación de cadenas usando solo espacios en blanco, etc.) Creo que los diseñadores de DTrace, que basaron la sintaxis D libremente en awk, tuve suficiente sentido común para NO copiar estas características, pero no puedo recordarlo de la parte superior de mi cabeza. Un ejemplo simple (contando el número de etiquetas ENTITY en un DTD, desde mi Mac):

$ cat printEntities.awk 
# This prints all lines where the string ENTITY occurs
/ENTITY/ {
  print $0
}
$ awk -f printEntities.awk < /usr/share/texinfo/texinfo.dtd | wc -l
     119

Si este pequeño script en cambio se escribiera con la llave en una línea propia, esto es lo que sucedería:

$ cat printAll.awk 
# Because of the brace placement, the print statement will be executed
# for all lines in the input file
# Lines containing the string ENTITY will be printed twice,
# because print is the default action, if no other action is specified
/ENTITY/
{ 
   print $0 
}
$ awk -f printAll.awk < /usr/share/texinfo/texinfo.dtd | wc -l
     603
$ /bin/cat < /usr/share/texinfo/texinfo.dtd | wc -l
     484
$ 
Anders S
fuente