Por que quase todos os tipos de linguagens de programação modernas (Go, Rust, Kotlin, Swift, Scala, Nim e até Python) sempre vêm após o nome da variável na declaração da variável, e não antes?
Por que x: int = 42
e não int x = 42
?
O último não é mais legível que o primeiro?
É apenas uma tendência ou existem razões realmente significativas por trás dessa solução?
programming-languages
language-design
syntax
Andre Polykanine
fonte
fonte
Respostas:
Todos os idiomas que você mencionou suportam inferência de tipo , o que significa que o tipo é uma parte opcional da declaração nesses idiomas, porque são inteligentes o suficiente para preenchê-los quando você fornece uma expressão de inicialização que tem um tipo facilmente determinado.
Isso importa porque colocar as partes opcionais de uma expressão mais à direita reduz a ambiguidade da análise e aumenta a consistência entre as expressões que usam essa parte e as que não o fazem. É mais simples analisar uma declaração quando você sabe que a
var
palavra - chave e o nome da variável são obrigatórios antes de acessar o material opcional. Em teoria, todas as coisas que facilitam a análise de computadores também devem melhorar a legibilidade geral para os seres humanos, mas isso é muito mais discutível.Este argumento fica especialmente forte quando se consideram todos os modificadores opcionais tipo que uma língua "não-moderno", como C ++ tem, como
*
para ponteiros,&
para referências,const
,volatile
e assim por diante. Depois de inserir vírgulas para várias declarações, você começa a obter algumas ambiguidades realmente estranhas, comoint* a, b;
não fazerb
um ponteiro.Até o C ++ agora suporta declarações "digite à direita" na forma de
auto x = int{ 4 };
, e possui algumas vantagens .fonte
var
essa fornece a maior parte da simplificação de análise.var
palavra - chave não anula o objetivo da notação nome-primeiro? Eu não vejo a vantagem de escrevervar userInput: String = getUserInput()
sobreString userInput = getUserInput()
. A vantagem seria relevante apenas seuserInput = getUserInput()
também for permitida, mas isso implicaria a declaração implícita de uma variável com escopo definido, o que eu acho bastante repugnante.var userInput = getUserInput()
ouauto userInput = getUserInput()
, o compilador sabegetUserInput()
retornosString
para que você não precise especificá-lo com a palavra-chave dedução de tipo.userInput = getUserInput()
é claro que usar antes de declarar.Sua premissa é falha em duas frentes:
Pascal, ML, CLU, Modula-2 e Miranda eram linguagens muito influentes; portanto, não é de surpreender que esse estilo de declaração de tipo permanecesse popular.
A legibilidade é uma questão de familiaridade. Pessoalmente, acho o chinês ilegível, mas aparentemente o povo chinês não. Tendo aprendido Pascal na escola, brincado com Eiffel, F♯, Haskell e Scala, e tendo olhado para TypeScript, Fortress, Go, Rust, Kotlin, Idris, Frege, Agda, ML, Ocaml,…, parece completamente natural para mim .
Se é uma tendência, é bastante persistente: como mencionei, remonta a cem anos em matemática.
Uma das principais vantagens de ter o tipo após o identificador é que é fácil deixar o tipo de fora, se você desejar que ele seja deduzido. Se suas declarações forem assim:
Então é trivial deixar de fora o tipo e inferi-lo assim:
Considerando que, se o tipo vier antes do identificador, desta forma:
Então, fica difícil para o analisador distinguir uma expressão de uma declaração:
A solução que os designers de linguagem geralmente apresentam é a introdução de uma palavra-chave "Não quero escrever um tipo" que deve ser escrita em vez do tipo:
Mas isso realmente não faz muito sentido: você basicamente precisa escrever explicitamente um tipo que diz que você não escreve um tipo. Hã? Seria muito mais fácil e sensato deixar de fora, mas isso torna a gramática muito mais complexa.
(E não vamos nem falar sobre os tipos de ponteiros de função em C.)
Os projetistas de várias das línguas mencionadas anteriormente abordaram esse assunto:
Go FAQ (consulte também: Sintaxe da declaração de Go ):
Perguntas frequentes sobre o Kotlin :
Programação em Scala :
Nota: os designers do Ceilão também documentaram por que usam a sintaxe do tipo de prefixo :
Pessoalmente, acho o "argumento" deles muito menos convincente do que os outros.
fonte
var
,auto
,let
ou semelhantes, não por que lado da variável a declaração de tipo está ligado.var Int x = 5
ou atéInt var x = 5
poderiam ser reduzidos paravar x = 5
."Your premise is flawed on two fronts"
Todos esses são mais recentes que C # ou D.func
em Go.Pascal faz isso também por sinal, e não é um novo idioma. Era uma linguagem acadêmica, projetada do zero.
Eu diria que é semanticamente mais claro começar com o nome da variável. O tipo é apenas um detalhe técnico. Se você quiser ler sua classe como o modelo de realidade atual, faz sentido colocar os nomes de suas entidades em primeiro lugar e sua implementação técnica por último.
C # e java derivam de C, então eles tiveram que respeitar a "arte anterior", para não confundir o programador experiente.
fonte
Em um exemplo tão simples, não há muita diferença, mas vamos torná-lo um pouco mais complexo:
int* a, b;
Esta é uma declaração válida e real em C, mas não faz o que parece intuitivamente que deveria fazer. Parece que estamos declarando duas variáveis do tipo
int*
, mas na verdade estamos declarando umaint*
e umaint
.Se o seu idioma colocar o tipo após o (s) nome (s) da variável em suas declarações, é impossível encontrar esse problema.
fonte
x, y *int;
dois*int
ou um*int
e umint
? Fazendoint*
ou*int
um símbolo em vez de dois iria resolvê-lo, ou usando um elemento sintática adicional, como o:
que poderia trabalhar em qualquer direção.:
ouas
, entre o nome e o tipo.x, y int
sem separador.x, y *int
significa "declarar duas variáveis, x e y, com o tipo ponteiro para int".int[] x, y
como duas matrizes. É apenas a tola sintaxe C que trata esses modificadores como operadores unários na variável (e uma mistura de prefixo e postfix, nada menos) que causa problemas.