Ho sentito molto che i nuovi linguaggi di programmazione sono tipizzati in modo dinamico, ma cosa significa in realtà quando diciamo che un linguaggio è digitato in modo dinamico rispetto a quello statico?
Ho sentito molto che i nuovi linguaggi di programmazione sono tipizzati in modo dinamico, ma cosa significa in realtà quando diciamo che un linguaggio è digitato in modo dinamico rispetto a quello statico?
Risposte:
Una lingua viene digitata staticamente se il tipo di una variabile è noto al momento della compilazione. Per alcune lingue ciò significa che come programmatore è necessario specificare il tipo di ciascuna variabile (ad esempio: Java, C, C ++); altre lingue offrono una qualche forma di inferenza di tipo , la capacità del sistema di tipi di dedurre il tipo di una variabile (es: OCaml, Haskell, Scala, Kotlin)
Il vantaggio principale qui è che tutti i tipi di controlli possono essere eseguiti dal compilatore, e quindi molti bug insignificanti vengono colti molto presto.
Esempi: C, C ++, Java, Rust, Go, Scala
Una lingua viene digitata in modo dinamico se il tipo è associato a valori di runtime e non denominato variabili / campi / ecc. Ciò significa che come programmatore puoi scrivere un po 'più velocemente perché non devi specificare i tipi ogni volta (a meno che tu non usi un linguaggio tipicamente statico con l' inferenza del tipo ).
Esempi: Perl, Ruby, Python, PHP, JavaScript
La maggior parte dei linguaggi di scripting ha questa funzione in quanto non esiste un compilatore che esegua comunque un controllo statico del tipo, ma potresti trovarti alla ricerca di un bug dovuto all'interprete che interpreta erroneamente il tipo di una variabile. Fortunatamente, gli script tendono ad essere piccoli, quindi i bug non hanno così tanti posti dove nascondersi.
La maggior parte delle lingue tipizzate dinamicamente ti consente di fornire informazioni sul tipo, ma non le richiedono. Un linguaggio attualmente in fase di sviluppo, Rascal , utilizza un approccio ibrido che consente la digitazione dinamica all'interno delle funzioni ma impone la digitazione statica per la firma della funzione.
I linguaggi di programmazione tipizzati staticamente eseguono il controllo del tipo (ovvero il processo di verifica e applicazione dei vincoli dei tipi) in fase di compilazione anziché in fase di esecuzione .
I linguaggi di programmazione tipicamente dinamici digitano il controllo in fase di esecuzione anziché in fase di compilazione .
Esempi di linguaggi tipizzati staticamente sono: - Java, C, C ++
Esempi di linguaggi tipizzati dinamicamente sono: - Perl, Ruby, Python, PHP, JavaScript
Ecco un esempio che contrappone il modo in cui Python (digitato in modo dinamico) e Go (digitato in modo statico) gestiscono un errore di tipo:
def silly(a):
if a > 0:
print 'Hi'
else:
print 5 + '3'
Python digita il controllo in fase di esecuzione e quindi:
silly(2)
Funziona perfettamente bene e produce l'output previsto Hi
. L'errore viene generato solo se viene colpita la linea problematica:
silly(-1)
produce
TypeError: unsupported operand type(s) for +: 'int' and 'str'
perché la linea pertinente è stata effettivamente eseguita.
D'altra parte fa il controllo del tipo in fase di compilazione:
package main
import ("fmt"
)
func silly(a int) {
if (a > 0) {
fmt.Println("Hi")
} else {
fmt.Println("3" + 5)
}
}
func main() {
silly(2)
}
Quanto sopra non verrà compilato, con il seguente errore:
invalid operation: "3" + 5 (mismatched types string and int)
runhaskell
, ad esempio.
In parole semplici: in una lingua tipicamente statica i tipi di variabili sono statici , il che significa che una volta impostata una variabile su un tipo, non è possibile cambiarla. Questo perché la digitazione è associata alla variabile anziché al valore a cui si riferisce.
Ad esempio in Java:
String str = "Hello"; //variable str statically typed as string
str = 5; //would throw an error since str is supposed to be a string only
D'altra parte: in una lingua tipizzata in modo dinamico , i tipi di variabili sono dinamici , il che significa che dopo aver impostato una variabile su un tipo, PUOI cambiarla. Questo perché la tipizzazione è associata al valore che assume piuttosto che alla variabile stessa.
Ad esempio in Python:
str = "Hello" # variable str is linked to a string value
str = 5 # now it is linked to an integer value; perfectly OK
Quindi, è meglio pensare alle variabili nei linguaggi tipizzati dinamicamente come semplici puntatori generici ai valori digitati.
Per riassumere, digitare descrive (o avrebbe dovuto descrivere) le variabili nella lingua piuttosto che la lingua stessa. Avrebbe potuto essere meglio utilizzato come linguaggio con variabili tipizzate staticamente rispetto a un linguaggio con variabili IMHO tipizzate dinamicamente .
I linguaggi tipicamente statici sono generalmente linguaggi compilati, quindi i compilatori controllano i tipi (ha perfettamente senso giusto? Poiché i tipi non possono essere modificati in un secondo momento in fase di esecuzione).
Le lingue tipizzate in modo dinamico vengono generalmente interpretate, quindi il controllo del tipo (se presente) avviene in fase di esecuzione quando vengono utilizzate. Questo ovviamente comporta un certo costo in termini di prestazioni ed è uno dei motivi per cui i linguaggi dinamici (ad es. Python, ruby, php) non si adattano bene a quelli digitati (java, c #, ecc.). Da un'altra prospettiva, le lingue tipizzate staticamente hanno un costo di avvio maggiore: di solito ti fa scrivere più codice, codice più difficile. Ma questo paga dopo.
La cosa buona è che entrambe le parti stanno prendendo in prestito funzioni dall'altra parte. I linguaggi tipizzati incorporano funzionalità più dinamiche, ad es. Generici e librerie dinamiche in c #, e i linguaggi dinamici includono un maggior controllo del tipo, ad es. Annotazioni dei tipi in Python o variante HACK di PHP, che di solito non sono fondamentali per il linguaggio e utilizzabili su richiesta.
Quando si tratta di selezionare la tecnologia, nessuna delle due parti ha una intrinseca superiorità rispetto all'altra. È solo una questione di preferenza se si desidera iniziare un maggiore controllo o flessibilità. scegli lo strumento giusto per il lavoro e assicurati di controllare ciò che è disponibile in termini di contrario prima di prendere in considerazione un passaggio.
http://en.wikipedia.org/wiki/Type_system
Digitazione statica
Si dice che un linguaggio di programmazione utilizza la tipizzazione statica quando il controllo del tipo viene eseguito durante il tempo di compilazione anziché in fase di esecuzione. Nella tipizzazione statica, i tipi sono associati a variabili e non a valori. I linguaggi tipizzati staticamente includono Ada, C, C ++, C #, JADE, Java, Fortran, Haskell, ML, Pascal, Perl (rispetto ai distinti scalari, array, hash e subroutine) e Scala. La tipizzazione statica è una forma limitata di verifica del programma (vedi sicurezza dei tipi): di conseguenza, consente di rilevare molti errori di tipo all'inizio del ciclo di sviluppo. I controllori statici del tipo valutano solo le informazioni sul tipo che possono essere determinate al momento della compilazione, ma sono in grado di verificare che le condizioni verificate valgano per tutte le possibili esecuzioni del programma, che elimina la necessità di ripetere i controlli del tipo ogni volta che il programma viene eseguito. L'esecuzione del programma può anche essere resa più efficiente (ovvero più veloce o con memoria ridotta) omettendo i controlli del tipo di runtime e abilitando altre ottimizzazioni.
Poiché valutano le informazioni sul tipo durante la compilazione e pertanto non dispongono di informazioni sul tipo disponibili solo in fase di esecuzione, i controlli di tipo statico sono conservativi. Rifiuteranno alcuni programmi che potrebbero essere ben educati in fase di esecuzione, ma che non possono essere determinati staticamente per essere ben tipizzati. Ad esempio, anche se un'espressione restituisce sempre true in fase di esecuzione, un programma contenente il codice
if <complex test> then 42 else <type error>
verrà rifiutato come non tipizzato, poiché un'analisi statica non può determinare che il ramo else non verrà preso. [1] Il comportamento conservativo dei controllori di tipi statici è vantaggioso quando viene valutato in modo falso di rado: un controllore di tipi statici può rilevare errori di tipo in percorsi di codice usati raramente. Senza il controllo statico del tipo, anche i test di copertura del codice con una copertura del codice del 100% potrebbero non essere in grado di trovare tali errori di tipo. I test di copertura del codice potrebbero non rilevare tali errori di tipo perché è necessario prendere in considerazione la combinazione di tutti i luoghi in cui vengono creati i valori e tutti i luoghi in cui viene utilizzato un determinato valore.
Le lingue tipicamente usate più comunemente non sono formalmente sicure. Hanno "scappatoie" nelle specifiche del linguaggio di programmazione che consentono ai programmatori di scrivere codice che elude la verifica eseguita da un controllore di tipo statico e quindi risolve una vasta gamma di problemi. Ad esempio, Java e la maggior parte dei linguaggi in stile C hanno il tipo di punzonatura e Haskell ha caratteristiche come unsafePerformIO: tali operazioni potrebbero non essere sicure in fase di esecuzione, in quanto possono causare comportamenti indesiderati a causa della digitazione errata dei valori durante l'esecuzione del programma.
Digitazione dinamica
Si dice che un linguaggio di programmazione sia tipizzato in modo dinamico, o semplicemente "dinamico", quando la maggior parte del suo controllo del tipo viene eseguito in fase di esecuzione anziché in fase di compilazione. Nella tipizzazione dinamica, i tipi sono associati a valori e non a variabili. I linguaggi tipizzati dinamicamente includono Groovy, JavaScript, Lisp, Lua, Objective-C, Perl (rispetto ai tipi definiti dall'utente ma non ai tipi incorporati), PHP, Prolog, Python, Ruby, Smalltalk e Tcl. Rispetto alla digitazione statica, la digitazione dinamica può essere più flessibile (ad esempio consentendo ai programmi di generare tipi e funzionalità in base ai dati di runtime), sebbene a scapito di meno garanzie a priori. Questo perché una lingua tipizzata in modo dinamico accetta e tenta di eseguire alcuni programmi che possono essere dichiarati non validi da un controllo di tipo statico.
La digitazione dinamica può comportare errori di tipo runtime, ovvero in fase di runtime un valore può avere un tipo imprevisto e viene applicata un'operazione senza senso per quel tipo. Questa operazione può verificarsi molto tempo dopo il luogo in cui è stato commesso l'errore di programmazione, ovvero il luogo in cui il tipo errato di dati è passato in un luogo che non dovrebbe avere. Questo rende il bug difficile da individuare.
I sistemi linguistici tipizzati dinamicamente, rispetto ai loro cugini tipicamente statici, effettuano meno controlli "in fase di compilazione" sul codice sorgente (ma verificheranno, ad esempio, che il programma sia sintatticamente corretto). I controlli di runtime possono potenzialmente essere più sofisticati, poiché possono utilizzare informazioni dinamiche e qualsiasi informazione presente durante la compilazione. D'altra parte, i controlli di runtime affermano solo che le condizioni valgono in una particolare esecuzione del programma e questi controlli vengono ripetuti per ogni esecuzione del programma.
Lo sviluppo in linguaggi tipicamente dinamici è spesso supportato da pratiche di programmazione come test unitari. Il test è una pratica chiave nello sviluppo di software professionale ed è particolarmente importante nei linguaggi tipizzati dinamicamente. In pratica, i test effettuati per garantire il corretto funzionamento del programma possono rilevare una gamma di errori molto più ampia rispetto al controllo statico del tipo, ma al contrario non possono cercare in modo così completo gli errori che sia il test che il controllo statico del tipo sono in grado di rilevare. I test possono essere incorporati nel ciclo di creazione del software, nel qual caso può essere considerato un controllo "tempo di compilazione", in quanto l'utente del programma non dovrà eseguire manualmente tali test.
Riferimenti
- Pierce, Benjamin (2002). Tipi e linguaggi di programmazione. MIT Premere. ISBN 0-262-16209-1.
myObject[remoteDataName]
. Quindi non c'è modo di sapere quale proprietà sceglierà o anche se si tratta di una proprietà valida.
La terminologia "tipizzata in modo dinamico" è purtroppo fuorviante. Tutte le lingue sono tipizzate staticamente e i tipi sono proprietà delle espressioni (non dei valori come alcuni pensano). Tuttavia, alcune lingue hanno un solo tipo. Questi sono chiamati linguaggi tipizzati uni. Un esempio di tale linguaggio è il calcolo lambda non tipizzato.
Nel calcolo lambda non tipizzato, tutti i termini sono termini lambda e l'unica operazione che può essere eseguita su un termine è applicarlo a un altro termine. Quindi tutte le operazioni comportano sempre una ricorsione infinita o un termine lambda, ma non segnalano mai un errore.
Tuttavia, se dovessimo aumentare il lambda calcolo tipizzato con i numeri primitive e le operazioni aritmetiche, allora potremmo eseguire operazioni senza senso, come l'aggiunta di due termini lambda insieme: (λx.x) + (λy.y)
. Si potrebbe sostenere che l'unica cosa sensata da fare è segnalare un errore quando ciò accade, ma per essere in grado di farlo, ogni valore deve essere taggato con un indicatore che indica se il termine è un termine lambda o un numero. L'operatore addizionale verificherà quindi che entrambi gli argomenti siano etichettati come numeri e, in caso contrario, segnalerà un errore. Si noti che questi tag non sono tipi, poiché i tipi sono proprietà dei programmi, non dei valori prodotti da tali programmi.
Un linguaggio univoco che lo fa si chiama dinamicamente.
Lingue come JavaScript, Python e Ruby sono tutte tipizzate uni. Ancora una volta, l' typeof
operatore in JavaScript e la type
funzione in Python hanno nomi fuorvianti; restituiscono i tag associati agli operandi, non i loro tipi. Allo stesso modo, dynamic_cast
in C ++ e instanceof
in Java non eseguire controlli di tipo.
"Quando il codice sorgente viene tradotto"
"Quando i tipi sono controllati"
5 + '3'
è un esempio di errore di tipo in linguaggi fortemente tipizzati come Go e Python, perché non consentono la "coercizione di tipo" -> la possibilità per un valore di cambiare tipo in determinati contesti come l'unione di due tipi. Le lingue debolmente digitate , come JavaScript, non genereranno un errore di tipo (risultati '53'
).
Le definizioni di "Statico e compilato" e "Dinamico e interpretato" sono abbastanza simili ... ma ricorda che è "quando i tipi sono controllati" rispetto a "quando il codice sorgente è tradotto".
Riceverai gli stessi errori di tipo indipendentemente dal fatto che la lingua sia compilata o interpretata ! È necessario separare questi termini concettualmente.
Dinamico, interpretato
def silly(a):
if a > 0:
print 'Hi'
else:
print 5 + '3'
silly(2)
Poiché Python viene interpretato e digitato in modo dinamico, traduce e verifica solo il codice su cui è in esecuzione. Il else
blocco non viene mai eseguito, quindi 5 + '3'
non viene mai nemmeno guardato!
E se fosse stato inserito staticamente?
Un errore di tipo verrebbe generato anche prima dell'esecuzione del codice. Esegue comunque il controllo del tipo prima del runtime anche se viene interpretato.
E se fosse stato compilato?
Il else
blocco verrebbe tradotto / esaminato prima del runtime, ma poiché è digitato in modo dinamico non genererebbe un errore! Le lingue tipizzate dinamicamente non controllano i tipi fino all'esecuzione e quella riga non viene mai eseguita.
Statico, compilato
package main
import ("fmt"
)
func silly(a int) {
if (a > 0) {
fmt.Println("Hi")
} else {
fmt.Println("3" + 5)
}
}
func main() {
silly(2)
}
I tipi vengono controllati prima di essere eseguiti (statici) e l'errore di tipo viene immediatamente rilevato! I tipi verrebbero comunque controllati prima del runtime se interpretati, con lo stesso risultato. Se fosse dinamico, non genererebbe errori anche se il codice sarebbe stato esaminato durante la compilazione.
Un linguaggio compilato avrà prestazioni migliori in fase di esecuzione se è tipizzato staticamente (rispetto dinamicamente); la conoscenza dei tipi consente l'ottimizzazione del codice macchina.
I linguaggi tipizzati staticamente hanno prestazioni migliori in fase di esecuzione intrinsecamente a causa della non necessità di controllare i tipi dinamicamente durante l'esecuzione (verifica prima dell'esecuzione).
Allo stesso modo, le lingue compilate sono più veloci in fase di esecuzione poiché il codice è già stato tradotto invece di dover "interpretare" / tradurlo al volo.
Si noti che entrambe le lingue compilate e tipicamente statiche avranno un ritardo prima di essere eseguite rispettivamente per la traduzione e il controllo del tipo.
La digitazione statica rileva gli errori in anticipo, invece di trovarli durante l'esecuzione (particolarmente utile per programmi lunghi). È più "rigoroso" in quanto non consente errori di tipo in qualsiasi parte del programma e spesso impedisce alle variabili di cambiare tipo, il che si difende ulteriormente da errori involontari.
num = 2
num = '3' // ERROR
La digitazione dinamica è più flessibile, cosa che alcuni apprezzano. In genere consente alle variabili di cambiare tipo, il che può causare errori imprevisti.
Linguaggi digitati staticamente : ogni variabile ed espressione è già nota al momento della compilazione.
( int a;
a può accettare solo valori di tipo intero in fase di esecuzione)
Esempi: C, C ++, Java
Linguaggi tipizzati dinamicamente : le variabili possono ricevere valori diversi in fase di esecuzione e il loro tipo è definito in fase di esecuzione.
( var a;
a può assumere qualsiasi tipo di valore in fase di esecuzione)
Esempi: Ruby, Python.
Verifica del tipo di lingue tipicamente statiche al momento della compilazione e il tipo NON può cambiare. (Non essere carino con i commenti di tipo casting, viene creata una nuova variabile / riferimento).
Controllo del tipo di lingue tipizzate dinamicamente in fase di esecuzione e il tipo di una variabile PU CAN essere modificato in fase di esecuzione.
Definizioni dolci e semplici, ma adatte all'esigenza: i linguaggi tipizzati staticamente vincolano il tipo a una variabile per l'intero ambito (Seg: SCALA) I linguaggi tipizzati dinamicamente legano il tipo al valore effettivo a cui fa riferimento una variabile.
I linguaggi tipizzati staticamente come C ++, Java e i linguaggi tipizzati dinamicamente come Python differiscono solo in termini di esecuzione del tipo di variabile. I linguaggi tipizzati staticamente hanno un tipo di dati statici per la variabile, qui il tipo di dati viene verificato durante la compilazione, quindi il debug è molto più semplice ... mentre i linguaggi tipizzati dinamicamente non fanno lo stesso, il tipo di dati viene controllato quale esecuzione del programma e quindi il il debug è un po 'difficile.
Inoltre hanno una differenza molto piccola e possono essere correlati con linguaggi fortemente tipizzati e debolmente tipizzati . Un linguaggio fortemente tipizzato non ti consente di utilizzare un tipo come un altro, ad es. C e C ++ ... mentre i linguaggi debolmente tipizzati consentono ad esempio python
Digitato staticamente
I tipi vengono controllati prima del runtime, quindi gli errori possono essere individuati in precedenza.
Esempi = c ++
Digitato dinamicamente
I tipi vengono controllati durante l'esecuzione.
Esempi = Python
Linguaggi tipizzati statici (il compilatore risolve le chiamate di metodo e i riferimenti di compilazione):
Linguaggi tipizzati dinamici (decisioni prese durante l'esecuzione del programma):
il linguaggio tipizzato dinamicamente aiuta a prototipare rapidamente i concetti dell'algoritmo senza il sovraccarico di pensare a quali tipi variabili debbano essere usati (che è una necessità nella lingua tipizzata staticamente ).
Digitazione statica: le lingue come Java e Scala sono tipizzate staticamente.
Le variabili devono essere definite e inizializzate prima di essere utilizzate in un codice.
per es. int x; x = 10;
System.out.println (x);
Digitazione dinamica: Perl è una lingua tipizzata dinamica.
Le variabili non devono essere inizializzate prima di essere utilizzate nel codice.
y = 10; usa questa variabile nella parte successiva del codice
$
), array ( @
) e hash ( %
). Il tipo di una variabile in Perl è noto al momento della compilazione e rimane lo stesso per il resto della durata della variabile.