Un autre langage que JavaScript a-t-il une différence entre les emplacements de début d'accolades (même ligne et ligne suivante)?

91

Aujourd'hui, alors que je lisais au hasard le livre O'Reilly sur les modèles JavaScript, j'ai trouvé une chose intéressante (page 27 pour référence).

En Javascript, dans certains cas, il y a une différence si l'emplacement de départ de l'accolade est différent.

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

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

Tandis que

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

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

Démo JSfiddle

Y a-t-il un autre langage qui ait un tel comportement? Si tel est le cas, je devrais certainement changer d’habitude .. :)

Je suis principalement préoccupé par PHP, C, C ++, Java et ruby.

Rajat Singhal
la source
1
Reproduit dans Chrome et IE9, bonne prise: P
gideon
4
La sensibilité aux espaces blancs peut être mise en œuvre - regardez python ou fortran en mode ligne - mais la sensibilité subtile aux espaces blancs est l'œuvre du diable. Gah! C'est aussi mauvais que faire!
dmckee --- ex-moderator chaton
C'est impressionnant! Bonne trouvaille!
CheckRaise
Maintenant, je veux savoir pourquoi javascript se comporte de cette façon.
CheckRaise
4
@CheckRaise: Je résume les règles ici: blogs.msdn.com/b/ericlippert/archive/2004/02/02/…
Eric Lippert

Réponses:

53

Tout langage qui ne repose pas sur des points-virgules (mais plutôt sur des nouvelles lignes) pour délimiter des instructions le permet potentiellement. Considérez Python :

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

Vous pourrez peut-être créer un cas similaire dans Visual Basic, mais je ne peux pas comprendre comment, car VB est assez restrictif dans l'emplacement des valeurs. Mais ce qui suit devrait fonctionner, sauf si l'analyseur statique se plaint d'un code inaccessible:

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

Parmi les langues que vous avez mentionnées, Ruby a la même propriété. PHP, C, C ++ et Java ne le font pas simplement parce qu'ils rejettent le retour à la ligne en tant qu'espace blanc et nécessitent des points-virgules pour délimiter les instructions.

Voici le code équivalent de l'exemple Python dans Ruby:

>> def foo
>>   return { 1 => 2 }
>> end
=> nil
>> def bar
>>   return
>>   { 1 => 2 }
>> end
=> nil
>> foo
=> {1=>2}
>> bar
=> nil
Konrad Rudolph
la source
2
Votre exemple de VB ne fait pas vraiment le point car VB ne permet jamais à une instruction de s'étendre sur plusieurs lignes à moins que vous n'utilisiez la séquence de continuation de ligne "_".
phoog
2
Ok, je retire le commentaire précédent parce que je viens de regarder la spécification, il y a des contextes dans lesquels VB.NET prend en charge les continuations de ligne implicites. Je doute qu'un programmeur VB expérimenté considère cet exemple comme un "gotcha", cependant, car c'est assez évident Throwet ce ex.GetBaseException()sont des lignes logiques séparées. Plus spécifiquement, étant donné que Basic utilise historiquement des lignes pour délimiter ses déclarations, un "gotcha" serait plus probablement une situation où un programmeur pense qu'il a créé une nouvelle instruction sur une nouvelle ligne logique, mais ne l'a pas fait.
phoog
@phoog C'est vrai, ce n'est absolument pas un piège.
Konrad Rudolph
40

L'interpréteur JavaScript ajoute automatiquement un ;à la fin de chaque ligne s'il n'en trouve pas (à quelques exceptions près, sans y entrer ici :).

Donc, fondamentalement, le problème n'est pas l'emplacement des accolades (qui représentent ici un objet littéral, pas un bloc de code comme dans la plupart des langages), mais cette petite "fonctionnalité" qui oblige votre premier exemple à return ;=> undefined. Vous pouvez vérifier le comportement de return dans la spécification ES5 .

Pour d'autres langues qui ont un comportement similaire, consultez la réponse de Konrad .

Alex Ciminian
la source
5
Réponse hautement votée, mais c'est en fait faux, désolé. L'explication est agréable mais veuillez corriger l'erreur.
Konrad Rudolph
La partie concernant JavaScript n'est pas fausse, la façon dont il se comporte est à cause de l'insertion de point-virgule qui oblige undefinedà être retourné. J'ai écrit un article sur les autres langues préfixées par afaik , alors prenez-le avec un grain de sel :).
Alex Ciminian
5
Mais ce n'est pas vrai que JS insère un point-virgule "à la fin de chaque ligne" "avec quelques exceptions"; plutôt, il n'insère généralement pas de point-virgule, et il n'y a que quelques cas où il le fait . C'est pourquoi cela provoque tant de pièges.
ruakh
26

Certainement. Le langage de programmation go de Google présente un comportement très similaire (bien qu'avec des effets différents). Comme expliqué ici:

En fait, ce qui se passe, c'est que le langage formel utilise des points-virgules, un peu comme en C ou Java, mais ils sont insérés automatiquement à la fin de chaque ligne qui ressemble à la fin d'une instruction. Vous n'avez pas besoin de les saisir vous-même.

..couper...

Cette approche permet d'obtenir un code propre et sans point-virgule. La seule surprise est qu'il est important de mettre l'accolade ouvrante d'une construction telle qu'une instruction if sur la même ligne que if; si vous ne le faites pas, certaines situations risquent de ne pas se compiler ou de donner un résultat erroné. La langue impose dans une certaine mesure le style d'accolade.

Secrètement, je pense que Rob Pike voulait juste une excuse pour exiger le style One True Brace.

Dave
la source
10
Cool, je ne savais pas à ce sujet :). Personnellement, je ne pense pas que l'insertion automatique de points-virgules soit une bonne idée. Cela peut introduire des bogues subtils que les personnes inexpérimentées avec la langue auront du mal à comprendre. Si vous voulez écrire du code sans point-virgule, je préfère la méthode python.
Alex Ciminian
Même sans langues @ Alex tout des points - virgules (VB) ont cette propriété. Tout comme Python, que vous préférez apparemment, même s'il gère cela de la même manière que JavaScript.
Konrad Rudolph
Je voterais pour, sauf que votre deuxième phrase est tellement fausse qu'elle me donne envie de voter contre. Je suppose qu'ils s'annulent. ;-)
ruakh
1
@ruakh voulez-vous dire "va faire exactement ça" ou faisiez-vous référence à la blague sur Rob Pike? Dans le premier cas, je pourrais reformuler en "aller présente le même comportement", dans le second, je suis désolé si mon sens de l'humour boiteux offense;)
Dave
1
Je veux dire le "Go fait exactement cela." La proposition originale d'insertion de point-virgule de Go contraste explicitement avec celle de JavaScript, expliquant: "Cette proposition peut vous rappeler la règle de point-virgule facultative de JavaScript, qui ajoute en fait des points-virgules pour corriger les erreurs d'analyse. La proposition Go est profondément différente", et c'est tout à fait vrai, à tous les niveaux: cela fonctionne différemment, il a des effets différents, et il n'a presque pas de pièges. (L'application OTBS, bien qu'énervante, n'est pas un piège, car c'est une exigence cohérente dans tout le code Go.)
ruakh
14

La réponse à cette question est assez simple. Toute langue qui a «l'insertion automatique de point-virgule» peut être en difficulté sur cette ligne. Le problème avec ça

return
{
     name: 'rajat'
};

..est que le moteur js insérera un point-virgule après l' return;instruction (et donc retournera undefined). Cet exemple est une bonne raison d'ouvrir les accolades toujours du côté droit et jamais du côté gauche également. Comme vous l'avez déjà correctement remarqué, s'il y a un crochet dans la même ligne, l'interprétateur le remarquera et ne pourra pas insérer un point-virgule.

jAndy
la source
6

FWIW, JSLint signale plusieurs avertissements avec cette syntaxe:

$ 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
la source
1

Le premier langage où je suis tombé sur ceci était awk (qui a aussi sa part de syntaxe "bizarreries"; points-virgules optionnels, concaténation de chaînes en utilisant uniquement des espaces et ainsi de suite ...) Je pense que les concepteurs de DTrace, qui ont basé la syntaxe D de manière lâche sur awk, avait assez de sens pour NE PAS copier ces fonctionnalités, mais je ne me souviens pas du haut de ma tête. Un exemple simple (compter le nombre de balises ENTITY dans une DTD, depuis mon 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 ce petit script était à la place écrit avec l'accolade sur une ligne propre, voici ce qui se passerait:

$ 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
la source