Why in nearly all modern programming languages (Go, Rust, Kotlin, Swift, Scala, Nim, even Python last version) types always come after the variable declaration, and not before?
La tua premessa è imperfetta su due fronti:
- Esistono nuovi linguaggi di programmazione che hanno il tipo prima l'identificatore. C♯, D, o Ceylon, per esempio.
- Avere il tipo dopo l'identificatore non è un fenomeno nuovo, risale almeno a Pascal (progettato nel 1968-1969, pubblicato nel 1970), ma in realtà è stato usato nella teoria dei tipi matematici, che inizia nel 1902. Fu usato anche in ML (1973), CLU (1974), Hope (1970), Modula-2 (1977-1985), Ada (1980), Miranda (1985), Caml (1985), Eiffel (1985), Oberon (1986), Modula-3 (1986-1988) e Haskell (1989).
Pascal, ML, CLU, Modula-2 e Miranda erano tutti lingue molto influenti, quindi non sorprende che questo tipo di dichiarazioni di tipo sia rimasto popolare.
Why x: int = 42
and not int x = 42
? Is the latter not more readable than the former?
La leggibilità è una questione di familiarità. Personalmente, trovo che i cinesi siano illeggibili, ma a quanto pare, i cinesi non lo fanno. Avendo imparato Pascal a scuola, dilettandomi con Eiffel, F♯, Haskell e Scala, e avendo osservato TypeScript, Fortress, Go, Rust, Kotlin, Idris, Frege, Agda, ML, Ocaml, ..., mi sembra del tutto naturale .
Is it just a trend or are there any really meaningful reasons behind such a solution?
Se si tratta di una tendenza, è piuttosto persistente: come ho detto, risale a cento anni in matematica.
Uno dei principali vantaggi di avere il tipo dopo l'identificatore è che è facile lasciare il tipo se vuoi che venga dedotto. Se le tue dichiarazioni sono così:
val i: Int = 10
Quindi è banale tralasciare il tipo e dedurre in questo modo:
val i = 10
Se invece il tipo precede l'identificatore in questo modo:
Int i = 10
Quindi inizia a diventare difficile per il parser distinguere un'espressione da una dichiarazione:
i = 10
La soluzione che i progettisti linguistici di solito escogitano è di introdurre una parola chiave "Non voglio scrivere un tipo" che deve essere scritta al posto del tipo:
var i = 10; // C♯
auto i = 10; // C++
Ma in realtà non ha molto senso: in pratica devi scrivere esplicitamente un tipo che dice che non scrivi un tipo. Eh? Sarebbe molto più semplice e sensato lasciarlo fuori, ma questo rende la grammatica molto più complessa.
(E non parliamo nemmeno dei tipi di puntatore a funzione in C.)
I progettisti di alcune delle suddette lingue hanno affrontato questo argomento:
-
Domande frequenti (vedi anche: Sintassi della dichiarazione di go ):
Why are declarations backwards?
They're only backwards if you're used to C. In C, the notion is that a variable is declared like an expression denoting its type, which is a nice idea, but the type and expression grammars don't mix very well and the results can be confusing; consider function pointers. Go mostly separates expression and type syntax and that simplifies things (using prefix *
for pointers is an exception that proves the rule). In C, the declaration
int* a, b;
declares a
to be a pointer but not b
; in Go
var a, b *int
declares both to be pointers. This is clearer and more regular. Also, the :=
short declaration form argues that a full variable declaration should present the same order as :=
so
var a uint64 = 1
has the same effect as
a := uint64(1)
Parsing is also simplified by having a distinct grammar for types that is not just the expression grammar; keywords such as func
and chan
keep things clear.
-
Domande frequenti su Kotlin :
Why have type declarations on the right?
We believe it makes the code more readable. Besides, it enables some nice syntactic features. For instance, it is easy to leave type annotations out. Scala has also proven pretty well this is not a problem.
-
Programmazione in Scala :
The major deviation from Java concerns the syntax for type annotations—it's "variable: Type
" instead of "Type variable
" in Java. Scala's postfix type syntax resembles Pascal, Modula-2, or Eiffel. The main reason for this deviation has to do with type inference, which often lets you omit the type of a variable or the return type of a method. Using the "variable: Type
" syntax this is easy—just leave out the colon and the type. But in C-style "Type variable
" syntax you cannot simply leave off the type—there would be no marker to start the definition anymore. You'd need some alternative keyword to be a placeholder for a missing type (C♯ 3.0, which does some type inference, uses var
for this purpose). Such an alternative keyword feels more ad-hoc and less regular than Scala's approach.
Nota: i progettisti di Ceylon hanno anche documentato il motivo per cui usano la sintassi del tipo di prefisso :
Prefix instead of postfix type annotations
Why do you follow C and Java in putting type annotations first, instead of Pascal and ML in putting them after the declaration name?
Perché pensiamo che questo:
shared Float e = ....
shared Float log(Float b, Float x) { ... }
È molto più facile leggere di questo:
shared value e: Float = ....
shared function log(b: Float, x: Float): Float { ... }
E semplicemente non capiamo come qualcuno possa pensare altrimenti!
Personalmente, trovo che il loro "argomento" sia molto meno convincente degli altri.