I never understood statements like this one. To be honest, even if you declare the return type of a function, you can and will forget it after you've written many lines of code, and you will still have to return to the line in which it's declared using the search function of your text editor to check it.
Non si tratta di te che dimentichi il tipo di reso - questo succederà sempre. Si tratta dello strumento in grado di farti sapere che hai dimenticato il tipo di reso.
As an addition, as functions are declared with type funcname()...
, whitout knowing type you will have to search over each line in which the function is called, because you only know funcname
, while in Python and the like you could just search for def funcname
or function funcname
which only happens once, at the declaration.
Questa è una questione di sintassi, che non è completamente correlata alla tipizzazione statica.
La sintassi della famiglia C è davvero ostile quando si vuole cercare una dichiarazione senza avere strumenti specializzati a vostra disposizione. Altre lingue non hanno questo problema. Vedi sintassi della dichiarazione di Rust:
fn funcname(a: i32) -> i32
More over, with REPLs it's trivial to test a function for it's return type with different inputs, while with statically typed languages you would need to add some lines of code and recompile everything just to know the type declared.
Qualsiasi lingua può essere interpretata e qualsiasi lingua può avere un REPL.
So, other than to know the return type of a function which clearly isn't a strong point of statically typed languages, how is static typing really helpful in bigger projects?
Risponderò in modo astratto.
Un programma consiste in varie operazioni e tali operazioni sono disposte come sono a causa di alcuni presupposti dello sviluppatore.
Alcune ipotesi sono implicite e altre sono esplicite. Alcuni presupposti riguardano un'operazione vicina a loro, alcuni riguardano un'operazione che li allontana. Un'assunzione è più facile da identificare quando è espressa in modo esplicito e il più vicino possibile ai luoghi in cui è importante il suo valore di verità.
Un bug è la manifestazione di un'ipotesi che esiste nel programma ma che non regge per alcuni casi. Per rintracciare un bug, dobbiamo identificare l'ipotesi errata. Per rimuovere il bug, dobbiamo rimuovere tale ipotesi dal programma o modificare qualcosa in modo tale che l'assunzione sia effettivamente valida.
Vorrei classificare le ipotesi in due tipi.
Il primo tipo sono le ipotesi che possono o meno tenere, a seconda degli input del programma. Per identificare un'assunzione errata di questo tipo, dobbiamo cercare nello spazio di tutti i possibili input del programma. Utilizzando ipotesi plausibili e pensiero razionale, possiamo restringere il problema e cercare in uno spazio molto più piccolo. Ma ancora, mentre un programma cresce anche un po ', il suo spazio di input iniziale cresce ad un ritmo enorme - al punto in cui può essere considerato infinito per tutti gli scopi pratici.
Il secondo tipo sono le ipotesi che sicuramente valgono per tutti gli input, o sono sicuramente errate per tutti gli input. Quando identifichiamo un'assunzione di questo tipo come errata, non abbiamo nemmeno bisogno di eseguire il programma o testare alcun input. Quando identifichiamo un'assunzione di questo tipo come corretta, abbiamo un sospetto in meno di cui preoccuparsi quando stiamo rintracciando un bug ( qualsiasi bug). Pertanto, c'è un valore nell'avere quante più ipotesi possibili appartengono a questo tipo.
Per inserire un'ipotesi nella seconda categoria (sempre vera o sempre falsa, indipendente dagli input), abbiamo bisogno di una quantità minima di informazioni disponibili nel luogo in cui viene formulata l'ipotesi. Attraverso il codice sorgente di un programma, le informazioni diventano obsolete rapidamente (ad esempio, molti compilatori non eseguono analisi interprocedurali, il che rende ogni chiamata un limite difficile per la maggior parte delle informazioni). Abbiamo bisogno di un modo per mantenere le informazioni richieste fresche (valide e vicine).
Un modo è quello di avere la fonte di queste informazioni il più vicino possibile al luogo in cui verrà consumata, ma che può essere poco pratica per la maggior parte dei casi d'uso. Un altro modo è quello di ripetere frequentemente le informazioni, rinnovandone la pertinenza attraverso il codice sorgente.
Come puoi già intuire, i tipi statici sono esattamente questo: i beacon di informazioni sul tipo sparsi sul codice sorgente. Queste informazioni possono essere utilizzate per mettere la maggior parte delle ipotesi sulla correttezza del tipo nella seconda categoria, il che significa che quasi tutte le operazioni possono essere classificate come sempre corrette o sempre errate rispetto alla compatibilità dei tipi.
Quando i nostri tipi non sono corretti, l'analisi ci fa risparmiare tempo portando il bug alla nostra attenzione presto piuttosto tardi. Quando i nostri tipi sono corretti, l'analisi ci fa risparmiare tempo assicurandoci che quando si verifica un errore, possiamo immediatamente escludere errori di tipo.