Pourquoi, dans presque tous les langages de programmation modernes (Go, Rust, Kotlin, Swift, Scala, Nim et même dernière version de Python), les types viennent toujours après le nom de la variable dans la déclaration de la variable et pas avant?
Pourquoi x: int = 42
et pas int x = 42
?
Ce dernier n'est-il pas plus lisible que l'ancien?
Est-ce juste une tendance ou y a-t-il des raisons vraiment significatives derrière cette solution?
programming-languages
language-design
syntax
André Polykanine
la source
la source
Réponses:
Toutes les langues que vous avez mentionnées prennent en charge l' inférence de type , ce qui signifie que le type est une partie facultative de la déclaration dans ces langues, car elles sont assez intelligentes pour le remplir elles-mêmes lorsque vous fournissez une expression d'initialisation ayant un type facilement déterminé.
Cela est important, car placer les parties facultatives d'une expression plus à droite réduit l'analyse d'ambiguïté et augmente la cohérence entre les expressions qui utilisent cette partie et celles qui ne le font pas. Il est simplement plus simple d'analyser une déclaration lorsque vous connaissez le
var
mot - clé et le nom de la variable sont obligatoires avant de passer aux éléments facultatifs. En théorie, toutes les choses qui facilitent l'analyse des ordinateurs devraient également améliorer la lisibilité pour les humains, mais c'est beaucoup plus discutable.Cet argument se particulièrement fort lorsque l' on considère tous les modificateurs de type option qu'une langue « non-moderne » comme C ++ a, comme
*
pour les pointeurs,&
les références,const
,volatile
et ainsi de suite. Une fois que vous insérez des virgules pour plusieurs déclarations, vous commencez à avoir des ambiguïtés vraiment étranges, commeint* a, b;
ne pas faire deb
pointeur.Même le C ++ supporte maintenant les déclarations "dactylographiées à droite" sous la forme de
auto x = int{ 4 };
, et il présente certains avantages .la source
var
que ceux-ci fournissent la majorité de la simplification de l'analyse.var
mot - clé ne va-t-elle pas à l'encontre de l' objectif de la notation nom-premier? Je ne vois pas l'avantage d'écrirevar userInput: String = getUserInput()
surString userInput = getUserInput()
. L'avantage ne serait pertinent que s'iluserInput = getUserInput()
est également autorisé, mais cela impliquerait la déclaration implicite d'une variable étendue, ce que je trouve plutôt abominable.var userInput = getUserInput()
ou bienauto userInput = getUserInput()
, le compilateur sait que lesgetUserInput()
retours reviennentString
. Vous n'avez donc pas à le spécifier avec le mot clé type deduction.userInput = getUserInput()
est bien sûr à utiliser avant de déclarer.Votre prémisse est défectueuse sur deux fronts:
Pascal, ML, CLU, Modula-2 et Miranda étaient tous des langages très influents. Il n’est donc pas étonnant que ce style de déclaration de caractères soit resté populaire.
La lisibilité est une question de familiarité. Personnellement, je trouve le chinois illisible, mais apparemment pas les Chinois. Avoir appris Pascal à l'école, côtoyé Eiffel, F♯, Haskell et Scala, et avoir regardé TypeScript, Fortress, Go, Rust, Kotlin, Idris, Frege, Agda, ML, Ocaml,…, cela me paraissait tout à fait naturel .
Si c'est une tendance, c'est assez persistant: comme je l'ai mentionné, cela remonte à cent ans en mathématiques.
L'un des principaux avantages d'avoir le type après l'identificateur est qu'il est facile de laisser le type en dehors si vous souhaitez l'inférer. Si vos déclarations ressemblent à ceci:
Ensuite, il est trivial de laisser le type et de l'inférer comme ceci:
Considérant que si le type précède l'identifiant comme ceci:
Ensuite, l'analyseur commence à avoir du mal à distinguer une expression d'une déclaration:
La solution généralement proposée par les concepteurs de langage consiste à introduire un mot clé "je ne veux pas écrire de type" qui doit être écrit à la place du type:
Mais cela n'a pas vraiment de sens: vous devez fondamentalement écrire explicitement un type qui dit que vous n'écrivez pas de type. Hein? Il serait beaucoup plus facile et plus judicieux de simplement laisser tomber, mais cela rend la grammaire beaucoup plus complexe.
(Et ne parlons même pas des types de pointeurs de fonction en C.)
Les concepteurs de plusieurs des langues susmentionnées ont pesé à ce sujet:
Go FAQ (voir aussi: Syntaxe de la déclaration de Go ):
FAQ Kotlin :
Programmation en Scala :
Remarque: les concepteurs de Ceylan ont également expliqué pourquoi ils utilisaient la syntaxe de type préfixe :
Personnellement, je trouve leur "argument" beaucoup moins convaincant que les autres.
la source
var
,auto
,let
ou similaires, non par quel côté de la variable la déclaration de type est activée.var Int x = 5
ou même lesInt var x = 5
deux pourraient être raccourcis àvar x = 5
."Your premise is flawed on two fronts"
Tous sont plus récents que C # ou D.func
dans Go.Pascal le fait aussi, d'ailleurs, et n'est pas un nouveau langage. C'était un langage académique cependant, conçu à partir de zéro.
Je dirais qu'il est sémantiquement plus clair de commencer par le nom de la variable. Le type est juste un détail technique. Si vous voulez lire votre classe comme un modèle de réalité, il est logique de mettre en premier le nom de vos entités et leur mise en œuvre technique.
C # et java étant issus de C, ils ont donc dû respecter "l'état de la technique" afin de ne pas confondre le programmeur expérimenté.
la source
Dans un exemple aussi simple, il n'y a pas beaucoup de différence, mais rendons-le un peu plus complexe:
int* a, b;
C'est une déclaration valide en C, mais elle ne fait pas ce à quoi elle ressemble intuitivement. On dirait que nous déclarons deux variables de type
int*
, mais en réalité nous en déclarons uneint*
et uneint
.Si votre langue place le type après le nom de la variable dans ses déclarations, le problème est impossible à résoudre.
la source
x, y *int;
deux*int
ou un*int
et unint
? Fabriquerint*
ou*int
un jeton au lieu de deux le résoudrait, ou utiliser un élément syntaxique supplémentaire comme le:
, qui pourrait fonctionner dans les deux sens.:
ouas
, entre le nom et le type.x, y int
sans séparateur.x, y *int
signifie "déclarer deux variables, x et y, avec le type pointeur-à-int".int[] x, y
comme deux tableaux. C'est juste la syntaxe C idiote qui traite ces modificateurs comme des opérateurs unaires sur la variable (et un mélange de préfixe et de postfix, rien de moins) qui pose problème.