Perché Kotlin richiede un tipo dopo una variabile, piuttosto che prima? [duplicare]

9

C, C ++, C #, Java, così come molti altri linguaggi tipizzati staticamente hanno il tipo prima della variabile come ( int a =5 , auto c = 4 , ecc.).

Lingue non staticamente tipizzate (come Javascript, base) usa var (o let ) prima del nome ( var a = "asd" )

Perché Kotlin, un linguaggio tipizzato staticamente, usa una miscela ( var i: Int )?

Perché non definirlo come ( Int i = 5 )? È un po 'meno la digitazione e non vedo il vantaggio nel modulo n. 2?

    
posta Charles Shiller 03.03.2016 - 23:51
fonte

5 risposte

15

Da 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.

Per "leggibilità" è probabile che i progettisti di Kotlin intendessero la stessa cosa Odersky significava per Scala : cioè scrivendo prima l'identificatore , sottolinei il suo nome sopra il suo tipo. Odersky sostiene che questo non importa molto per i nomi brevi come Int , ma conta di più quando hai SomeLongType<OfOtherLongType> . Nelle sue parole:

val shapeInfo: HashMap[Shape, (String, String)] = makeInfo()

It says clearly

  • We define a value here, not a variable or method (val)
  • The name of the thing we define is shapeInfo
  • If you care about it, here's the type (HashMap[...])
    
risposta data 04.03.2016 - 00:33
fonte
13

C, c++, C#, Java, as well as many other statically typed languages have the type before variable like (int a =5, auto c = 4, etc).

Prima di tutto: il design della lingua non è un concorso di popolarità.

Ma anche se lo fosse, Kotlin sarebbe probabilmente dalla parte dei vincitori: Pascal, Modula, Modula-2, Oberon, Oberon-2, Modula-3, Ada, Eiffel, ML, Caml, OCaml, F #, Haskell, Miranda, Go, Scala, Idris, Frege sono solo alcune delle lingue che posso nominare in cima alla mia testa, e ce ne sono molte altre.

Non-statically typed languages (such as Javascript, basic) use var (or let) before the name (var a = "asd")

E altri no, come Python o Ruby.

Why not define it as (Int i = 5)? It's a bit less typing and I don't see the advantage in form #2?

Ci sono molti vantaggi. Alcuni sono:

  • Familiarità: molte lingue hanno il tipo dopo l'identificatore. Seguendo il loro esempio, Kotlin sarà immediatamente comprensibile dai programmatori che hanno esperienza in una di queste lingue.
  • La sintassi per Type Inference è semplice: basta lasciare il tipo, verrà analizzato esattamente come prima, solo senza il tipo. Se hai il tipo prima dell'identificatore, lasciandolo fuori cambia il modo in cui viene analizzato (supponendo che analizziamo da sinistra a destra). Ciò significa che hai bisogno di una sintassi più complessa, o hai bisogno di un tipo "falso" che il programmatore deve usare per indicare esplicitamente che il tipo è implicito (il che è abbastanza ridicolo). Ad esempio, C ++ ( auto ) e C # ( var ) hanno questo problema.
risposta data 04.03.2016 - 03:28
fonte
6

È perché quando si hanno funzioni di ordine superiore (funzioni che possono assumere altre funzioni come parametri o restituire altre funzioni), il tipo dopo la variabile rende le dichiarazioni del tipo lette da sinistra a destra invece che in una spirale strana. / p>

Considera questo esempio da un eccellente blog sul perché golang ha seguito questa strada :

int (*fp)(int (*ff)(int x, int y), int b)

È piuttosto difficile dire quale sia un tipo di ritorno e cosa sia un argomento, e hai bisogno di parentesi per disambiguare molto di questo. È una delle ragioni principali per cui le persone evitano i puntatori di funzioni come la piaga in C. Con il tipo alla fine, quell'ambiguità viene rimossa senza parentesi.

Come sottolineato da Amon, i linguaggi recenti della famiglia C sono più simili a:

std::function<int(std::function<int(int x, int y)> ff, int b)> fp

Sì, anche qui viene rimossa l'ambiguità, ma era anche per l'esempio C. Abbiamo appena scelto un diverso set di delimitatori (la funzione std :: function < >) per disambiguare. Abbiamo ancora una sintassi speciale per la dichiarazione dei puntatori di funzioni che è al di fuori della normale sintassi della dichiarazione del tipo. Non leggiamo più a spirale, il che è un grande miglioramento, ma non abbiamo nemmeno aggiunto i generici nel mix e abbiamo già una firma di tipo piuttosto lunga e impegnata.

Confronta con la firma del tipo postfissa per una dichiarazione di funzione:

def f(ff: (Int, Int) => Int, b: Int): Int

Questo si legge molto chiaramente, da sinistra a destra. Posso scorrere il lato sinistro della pagina e trovare facilmente i nomi delle mie funzioni. È facile da analizzare, perché hai già una dichiarazione, basta aggiungere un : type signature opzionale alla fine. Dichiarare una variabile che contiene un riferimento a questa funzione è quasi identica:

val fp: (ff: (Int, Int) => Int, Int) => Int = f
// although usually because of type inference you can just write:
val fp = f

Anche qui utilizziamo il colon come delimitatore per risolvere l'ambiguità, ma il delimitatore sull'altro lato era già lì, o la virgola o il paren di chiusura o qualsiasi altro token, quindi è molto meno invadente. Questo semplicemente non è possibile con type-first. devi circondare la dichiarazione della funzione, in un modo o nell'altro.

Quando usi sempre le funzioni di ordine superiore, è utile un po 'di leggibilità aggiunta. Ecco perché le lingue che intendono supportare in modo idiomatico le funzioni di ordine superiore a un certo punto usano l'ultima sintassi tipo-ultima dall'inizio.

    
risposta data 04.03.2016 - 00:44
fonte
4

Non è una questione di dinamica rispetto a statica. Si tratta di "sembrare come C" e "non sembra C". Le lingue C ++, Java e C # hanno seguito la tradizione di "sembrare come C" per motivi di familiarità. Altre lingue, statiche o dinamiche hanno scelto sintassi diverse.

La sintassi type-before-identifier ha lo svantaggio di non funzionare altrettanto bene con le annotazioni di tipo facoltative. C non ha avuto inferenza di tipo, quindi non era un problema. Inizialmente, C # non aveva l'eteri di inferenza del tipo, quindi quando è stato aggiunto ha portato a una sintassi piuttosto incoerente. Il vantaggio è che sembra "C", quindi inizialmente è più familiare agli sviluppatori, anche se oggettivamente non è una sintassi logica.

Java segue la tradizione del "aspetto come C", quindi per offrire miglioramenti su Java, Kotlin può rompere con la tradizione C nei casi in cui ritengono che possa portare a una sintassi migliore. (Se la familiarità fosse la cosa di solo che contava, non ci sarebbe alcuna giustificazione per Kotlin in primo luogo)

    
risposta data 04.03.2016 - 16:41
fonte
1

C, c++, C#, Java, as well as many other statically typed languages have the type before variable like (int a =5, auto c = 4, etc).

Questo è vero, ma lontano dall'intera storia. Esistono anche alcune lingue tipizzate in modo statico come Pascal, Delphi, Ada, Modula II e III, Eiffel e Go che mettono il nome della variabile prima del tipo, ad esempio:

var
    a : integer;
    b : integer;

Quindi, almeno a questo riguardo, la sintassi di Kotlin è più simile a Pascal che a C. Sebbene non sia ciò che è più popolare al momento, ci sono sicuramente molti precedenti anche per questo.

Sul motivo per cui lo faresti: una ragione è che generalmente è più facile da analizzare (sia per le persone che per i compilatori, almeno nella mia esperienza).

    
risposta data 04.03.2016 - 01:48
fonte

Leggi altre domande sui tag