Alguma outra linguagem diferente de JavaScript tem uma diferença entre os locais de início da chave (mesma linha e próxima linha)?

91

Hoje, enquanto eu estava lendo aleatoriamente o livro da O'Reilly sobre padrões de JavaScript, descobri uma coisa interessante (página 27 para referência).

Em Javascript, em alguns casos, há uma diferença se o local de início da chave for diferente.

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

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

Enquanto

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

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

JSfiddle Demo

Alguma outra língua por aí tem esse comportamento? Se sim, então eu teria que mudar meu hábito com certeza .. :)

Estou principalmente preocupado com PHP, C, C ++, Java e ruby.

Rajat Singhal
fonte
1
Reproduzido no Chrome e no IE9, boa pegada: P
gideon
4
A sensibilidade ao espaço em branco pode funcionar - olhe para python ou modo de linha fortran - mas a sensibilidade sutil do espaço em branco é obra do diabo. Gah! Isso é tão ruim quanto fazer!
dmckee --- ex-gatinho moderador
Isso é impressionante! Belo achado!
CheckRaise de
Agora eu quero saber por que o javascript se comporta dessa maneira.
CheckRaise de
4
@CheckRaise: Resumo as regras aqui: blogs.msdn.com/b/ericlippert/archive/2004/02/02/…
Eric Lippert

Respostas:

53

Qualquer linguagem que não dependa de ponto-e-vírgula (mas em vez de novas linhas) para delimitar as instruções permite isso. Considere Python :

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

Você pode ser capaz de construir um caso semelhante no Visual Basic, mas de repente não consigo descobrir como porque o VB é muito restritivo em onde os valores podem ser colocados. Mas o seguinte deve funcionar, a menos que o analisador estático reclame sobre código inacessível:

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

Das linguagens que você mencionou, Ruby tem a mesma propriedade. PHP, C, C ++ e Java não simplesmente porque descartam a nova linha como espaço em branco e exigem ponto-e-vírgula para delimitar as instruções.

Aqui está o código equivalente do exemplo Python em Ruby:

>> def foo
>>   return { 1 => 2 }
>> end
=> nil
>> def bar
>>   return
>>   { 1 => 2 }
>> end
=> nil
>> foo
=> {1=>2}
>> bar
=> nil
Konrad Rudolph
fonte
2
Seu exemplo VB não mostra exatamente o ponto porque o VB nunca permite que uma instrução ocupe várias linhas, a menos que você use a sequência de continuação de linha "_".
phoog de
2
Ok, retiro o comentário anterior porque acabei de olhar as especificações, existem alguns contextos nos quais o VB.NET oferece suporte a continuações de linha implícitas. Eu duvido que qualquer programador VB experiente consideraria este exemplo um "pegadinha", já que é bastante óbvio que Throwe ex.GetBaseException()são linhas lógicas separadas. Mais especificamente, visto que o Basic historicamente usa linhas para delimitar suas declarações, um "pegadinha" seria mais provavelmente uma situação em que um programador pensa que criou uma nova declaração em uma nova linha lógica, mas não o fez.
phoog de
@phoog Verdade, não é absolutamente um problema.
Konrad Rudolph
40

O interpretador JavaScript adiciona automaticamente um ;no final de cada linha se não encontrar um (com algumas exceções, não entrando nelas aqui :).

Então, basicamente, o problema não é a localização dos colchetes (que aqui representam um objeto literal, não um bloco de código como na maioria das linguagens), mas este pequeno "recurso" que força seu primeiro exemplo a return ;=> undefined. Você pode verificar o comportamento de return na especificação ES5 .

Para outras linguagens com comportamento semelhante, verifique a resposta de Konrad .

Alex Ciminian
fonte
5
Resposta altamente votada, mas na verdade errada, desculpe. A explicação é boa, mas corrija o erro.
Konrad Rudolph
A parte sobre JavaScript não está errada, a maneira como ele se comporta é por causa da inserção de ponto-e-vírgula que força o undefinedretorno. Eu escrevi um trecho sobre as outras línguas com o prefixo afaik , então aceite isso com cautela :).
Alex Ciminian
5
Mas não é verdade que JS insere um ponto e vírgula "no final de cada linha" "com algumas exceções"; em vez disso, geralmente não insere um ponto-e-vírgula e há apenas alguns casos em que o faz . É por isso que causa tantos problemas.
ruakh 09/02/12
26

Certamente. A linguagem de programação go do Google exibe um comportamento muito semelhante (embora com efeitos diferentes). Conforme explicado lá:

Na verdade, o que acontece é que a linguagem formal usa ponto-e-vírgula, assim como em C ou Java, mas eles são inseridos automaticamente no final de cada linha que parece o final de uma instrução. Você não precisa digitá-los sozinho.

..recorte...

Essa abordagem torna o código de aparência limpa e sem ponto-e-vírgula. A única surpresa é que é importante colocar a chave de abertura de uma construção como uma instrução if na mesma linha de if; se não fizer isso, há situações que podem não ser compiladas ou podem dar o resultado errado. A linguagem força o estilo de chave em certa medida.

Secretamente, acho que Rob Pike só queria uma desculpa para exigir o One True Brace Style.

Dave
fonte
10
Legal, não sabia disso :). Pessoalmente, não acho que a inserção automática de ponto-e-vírgula seja uma boa ideia. Ele pode introduzir bugs sutis que pessoas inexperientes com a linguagem terão dificuldade em descobrir. Se você quiser escrever código livre de ponto-e-vírgula, prefiro o método python.
Alex Ciminian
@Alex Mesmo linguagens sem qualquer ponto-e-vírgula (VB) têm esta propriedade. E o mesmo acontece com o Python, que você aparentemente prefere, embora ele lide com isso de forma idêntica ao JavaScript.
Konrad Rudolph
Eu votaria a favor, exceto que sua segunda frase é tão completamente errada que me faz querer votar negativamente. Eu acho que eles cancelaram. ;-)
ruakh
1
@ruakh, você quer dizer "go faz exatamente isso" ou estava se referindo à piada sobre rob pike? No primeiro caso, eu poderia reformular para "ir exibe o mesmo comportamento", no último, sinto muito se meu senso de humor coxo ofende;)
Dave
1
Quero dizer, o "Go faz exatamente isso." A proposta original para a inserção de ponto-e-vírgula do Go contrasta explicitamente com a do JavaScript, explicando: "Esta proposta pode lembrá-lo da regra de ponto-e-vírgula opcional do JavaScript, que na verdade adiciona ponto-e-vírgula para corrigir erros de análise. A proposta de Go é profundamente diferente", e isso é bem verdade, em todos os níveis: funciona de maneira diferente, tem efeitos diferentes e quase não tem pegadinhas. (A aplicação de OTBS, embora irritante, não é um problema, já que é um requisito consistente em todo o código Go.)
ruakh
14

A resposta a essa pergunta é bastante fácil. Qualquer idioma com "inserção automática de ponto-e-vírgula" pode ter problemas nessa linha. O problema com isso

return
{
     name: 'rajat'
};

..é que o mecanismo js irá inserir um ponto-e-vírgula após a return;instrução (e, portanto, retornar undefined). Este exemplo é um bom motivo para abrir as chaves sempre do lado direito e nunca do lado esquerdo também. Como você já percebeu corretamente, se houver uma chave na mesma linha, o interpretador perceberá e não poderá inserir o ponto-e-vírgula.

Andy
fonte
6

FWIW, JSLint relata vários avisos com essa sintaxe:

$ 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
fonte
1

A primeira linguagem em que me deparei com isso foi awk (que também tem sua parcela de "esquisitices" de sintaxe; ponto e vírgula opcional, concatenação de string usando apenas espaços em branco e assim por diante ...) Acho que os designers do DTrace, que basearam a sintaxe D vagamente no awk, tive bastante bom senso para NÃO copiar esses recursos, mas não consigo me lembrar de cara. Um exemplo simples (contando o número de tags ENTITY em um DTD, do meu 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

Se este pequeno script fosse escrito com a chave em uma linha própria, isto é o que aconteceria:

$ 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
fonte