Quali sono i vantaggi e i limiti delle lingue di tipo dinamico rispetto alle lingue di tipo statico?
Vedi anche : cos'è l'amore per i linguaggi dinamici (un filo molto più polemico ...)
Quali sono i vantaggi e i limiti delle lingue di tipo dinamico rispetto alle lingue di tipo statico?
Vedi anche : cos'è l'amore per i linguaggi dinamici (un filo molto più polemico ...)
Risposte:
La capacità dell'interprete di dedurre conversioni di tipo e tipo velocizza i tempi di sviluppo, ma può anche provocare errori di runtime che non è possibile ottenere in un linguaggio tipicamente statico in cui vengono rilevati al momento della compilazione. Ma quale è il migliore (o anche se è sempre vero) è discusso caldamente nella comunità in questi giorni (e da molto tempo).
Una buona idea della questione è quella della tipizzazione statica ove possibile, la digitazione dinamica quando necessario: la fine della guerra fredda tra i linguaggi di programmazione di Erik Meijer e Peter Drayton di Microsoft:
I sostenitori della tipizzazione statica sostengono che i vantaggi della tipizzazione statica includono il rilevamento precoce di errori di programmazione (ad es. Impedire l'aggiunta di un numero intero a un valore booleano), una migliore documentazione sotto forma di firme di tipo (ad es. Incorporando numero e tipi di argomenti quando si risolvono i nomi), altro opportunità di ottimizzazione del compilatore (ad es. sostituzione di chiamate virtuali con chiamate dirette quando il tipo esatto di ricevitore è noto staticamente), maggiore efficienza di runtime (ad es. non tutti i valori devono avere un tipo dinamico) e una migliore esperienza di sviluppo in fase di progettazione (ad es. il tipo di ricevitore, l'IDE può presentare un menu a discesa di tutti i membri applicabili). I fanatici della tipizzazione statica cercano di farci credere che "i programmi ben digitati non possono andare storti". Anche se questo suona sicuramente impressionante, è un'affermazione piuttosto vacua. Il controllo statico del tipo è un'astrazione in fase di compilazione del comportamento in fase di esecuzione del programma e quindi è necessariamente solo parzialmente sana e incompleta. Ciò significa che i programmi possono comunque andare storto a causa di proprietà che non vengono monitorate dal controllo del tipo e che ci sono programmi che, sebbene non possano andare male, non possono essere controllati. L'impulso a rendere la tipizzazione statica meno parziale e più completa fa sì che i sistemi di tipi diventino eccessivamente complicati ed esotici, come testimoniano concetti come "tipi fantasma" [11] e "tipi traballanti" [10]. È come provare a correre una maratona con una palla e una catena legate alla gamba e gridare trionfalmente che ce l'hai quasi fatta anche se sei stato salvato dopo il primo miglio. Il controllo statico del tipo è un'astrazione in fase di compilazione del comportamento in fase di esecuzione del programma e quindi è necessariamente solo parzialmente sana e incompleta. Ciò significa che i programmi possono comunque andare storto a causa di proprietà che non vengono monitorate dal controllo del tipo e che ci sono programmi che, sebbene non possano andare male, non possono essere controllati. L'impulso a rendere la tipizzazione statica meno parziale e più completa fa sì che i sistemi di tipi diventino eccessivamente complicati ed esotici, come testimoniano concetti come "tipi fantasma" [11] e "tipi traballanti" [10]. È come provare a correre una maratona con una palla e una catena legate alla gamba e gridare trionfalmente che ce l'hai quasi fatta anche se sei stato salvato dopo il primo miglio. Il controllo statico del tipo è un'astrazione in fase di compilazione del comportamento in fase di esecuzione del programma e quindi è necessariamente solo parzialmente sana e incompleta. Ciò significa che i programmi possono comunque andare storto a causa di proprietà che non vengono monitorate dal controllo del tipo e che ci sono programmi che, sebbene non possano andare male, non possono essere controllati. L'impulso a rendere la tipizzazione statica meno parziale e più completa fa sì che i sistemi di tipi diventino eccessivamente complicati ed esotici, come testimoniano concetti come "tipi fantasma" [11] e "tipi traballanti" [10]. È come provare a correre una maratona con una palla e una catena legate alla gamba e gridare trionfalmente che ce l'hai quasi fatta anche se sei stato salvato dopo il primo miglio. e quindi è necessariamente solo parzialmente sano e incompleto. Ciò significa che i programmi possono comunque andare storto a causa di proprietà che non vengono monitorate dal controllo del tipo e che ci sono programmi che, sebbene non possano andare male, non possono essere controllati. L'impulso a rendere la tipizzazione statica meno parziale e più completa fa sì che i sistemi di tipi diventino eccessivamente complicati ed esotici, come testimoniano concetti come "tipi fantasma" [11] e "tipi traballanti" [10]. È come provare a correre una maratona con una palla e una catena legate alla gamba e gridare trionfalmente che ce l'hai quasi fatta anche se sei stato salvato dopo il primo miglio. e quindi è necessariamente solo parzialmente sano e incompleto. Ciò significa che i programmi possono comunque andare storto a causa di proprietà che non vengono monitorate dal controllo del tipo e che ci sono programmi che, sebbene non possano andare male, non possono essere controllati. L'impulso a rendere la tipizzazione statica meno parziale e più completa fa sì che i sistemi di tipi diventino eccessivamente complicati ed esotici, come testimoniano concetti come "tipi fantasma" [11] e "tipi traballanti" [10]. È come provare a correre una maratona con una palla e una catena legate alla gamba e gridare trionfalmente che ce l'hai quasi fatta anche se sei stato salvato dopo il primo miglio. e che ci sono programmi che pur non potendo sbagliare non possono essere controllati dal tipo. L'impulso a rendere la tipizzazione statica meno parziale e più completa fa sì che i sistemi di tipi diventino eccessivamente complicati ed esotici, come testimoniano concetti come "tipi fantasma" [11] e "tipi traballanti" [10]. È come provare a correre una maratona con una palla e una catena legate alla gamba e gridare trionfalmente che ce l'hai quasi fatta anche se sei stato salvato dopo il primo miglio. e che ci sono programmi che pur non potendo sbagliare non possono essere controllati dal tipo. L'impulso a rendere la tipizzazione statica meno parziale e più completa fa sì che i sistemi di tipi diventino eccessivamente complicati ed esotici, come testimoniano concetti come "tipi fantasma" [11] e "tipi traballanti" [10]. È come provare a correre una maratona con una palla e una catena legate alla gamba e gridare trionfalmente che ce l'hai quasi fatta anche se sei stato salvato dopo il primo miglio.
I sostenitori di linguaggi tipizzati dinamicamente sostengono che la tipizzazione statica è troppo rigida e che la morbidezza dei linguaggi dinamici li rende ideali per prototipi di sistemi con requisiti mutevoli o sconosciuti o che interagiscono con altri sistemi che cambiano in modo imprevedibile (integrazione di dati e applicazioni). Naturalmente, i linguaggi tipizzati dinamicamente sono indispensabili per affrontare comportamenti di programma veramente dinamici come l'intercettazione di metodi, il caricamento dinamico, il codice mobile, la riflessione sul runtime, ecc. Nella madre di tutti gli articoli sullo scripting [16], John Ousterhout sostiene che i sistemi tipizzati staticamente i linguaggi di programmazione rendono il codice meno riutilizzabile, più dettagliato, non più sicuro e meno espressivo dei linguaggi di script tipizzati dinamicamente. Questo argomento è letteralmente pappagallo da molti sostenitori di linguaggi di script tipizzati in modo dinamico. Sosteniamo che questo è un errore e rientra nella stessa categoria dell'argomentazione secondo cui l'essenza della programmazione dichiarativa sta eliminando l'incarico. O come dice John Hughes [8], è un'impossibilità logica di rendere un linguaggio più potente omettendo le funzionalità. Difendere il fatto che ritardare tutto il controllo del tipo al runtime sia una buona cosa, sta giocando tattiche di struzzo con il fatto che gli errori dovrebbero essere colti il più presto possibile nel processo di sviluppo. è un'impossibilità logica di rendere più potente un linguaggio omettendo le funzionalità. Difendere il fatto che ritardare tutto il controllo del tipo al runtime sia una buona cosa, sta giocando tattiche di struzzo con il fatto che gli errori dovrebbero essere colti il più presto possibile nel processo di sviluppo. è un'impossibilità logica di rendere più potente un linguaggio omettendo le funzionalità. Difendere il fatto che ritardare tutto il controllo del tipo al runtime sia una buona cosa, sta giocando tattiche di struzzo con il fatto che gli errori dovrebbero essere colti il più presto possibile nel processo di sviluppo.
I sistemi di tipo statico cercano di eliminare staticamente determinati errori, ispezionando il programma senza eseguirlo e tentando di dimostrare la solidità sotto certi aspetti. Alcuni sistemi di tipi sono in grado di rilevare più errori di altri. Ad esempio, C # può eliminare le eccezioni del puntatore null se usato correttamente, mentre Java non ha tale potere. Twelf ha un sistema di tipi che garantisce effettivamente che le prove terminino , "risolvendo" il problema di interruzione .
Tuttavia, nessun sistema di tipi è perfetto. Per eliminare una particolare classe di errori, devono anche rifiutare alcuni programmi perfettamente validi che violano le regole. Questo è il motivo per cui Twelf non risolve davvero il problema dell'arresto, lo evita semplicemente lanciando un gran numero di prove perfettamente valide che si risolvono in modo strano. Allo stesso modo, il sistema di tipi Java rifiuta l' PersistentVector
implementazione di Clojure a causa dell'uso di array eterogenei. Funziona in fase di esecuzione, ma il sistema di tipi non può verificarlo.
Per questo motivo, la maggior parte dei sistemi di tipo fornisce "escape", modi per sovrascrivere il controllo statico. Per la maggior parte delle lingue, questi prendono la forma del casting, sebbene alcuni (come C # e Haskell) abbiano intere modalità contrassegnate come "non sicure".
Soggettivamente, mi piace la digitazione statica. Implementato correttamente (suggerimento: non Java), un sistema di tipo statico può essere di grande aiuto per eliminare gli errori prima che si blocchino il sistema di produzione. I linguaggi tipizzati dinamicamente tendono a richiedere più test unitari, il che è noioso il più delle volte. Inoltre, i linguaggi tipizzati staticamente possono avere determinate caratteristiche che sono impossibili o non sicure nei sistemi di tipo dinamico (vengono in mente conversioni implicite ). È tutta una questione di requisiti e gusto soggettivo. Non costruirò più il prossimo Eclipse in Ruby di quanto proverei a scrivere uno script di backup in Assembly o patch un kernel usando Java.
Oh, e le persone che affermano che "la digitazione x è 10 volte più produttiva di quella y " soffiano semplicemente fumo. La digitazione dinamica può "sentirsi" più veloce in molti casi, ma perde terreno quando si tenta effettivamente di far funzionare l' applicazione fantasia . Allo stesso modo, la digitazione statica può sembrare la rete di sicurezza perfetta, ma uno sguardo ad alcune delle definizioni di tipo generico più complicate in Java fa sì che la maggior parte degli sviluppatori si affretti a cercare paraocchi. Anche con sistemi di tipo e produttività, non esiste un proiettile d'argento.
Nota finale: non preoccuparti delle prestazioni quando si confronta statica con la digitazione dinamica. I JIT moderni come V8 e TraceMonkey si avvicinano pericolosamente alle prestazioni del linguaggio statico. Inoltre, il fatto che Java si compili effettivamente in un linguaggio intermedio intrinsecamente dinamico dovrebbe essere un suggerimento che per la maggior parte dei casi, la digitazione dinamica non è l'enorme killer delle prestazioni che alcune persone si rendono conto di essere.
dadd
perché sa in anticipo che gli operandi sono double
s.
Bene, entrambi sono molto, molto, molto molto fraintesi e anche due cose completamente diverse. che non si escludono a vicenda .
I tipi statici sono una limitazione della grammatica della lingua. Si potrebbe dire che i linguaggi tipicamente statici rigorosamente non siano contestuali. La semplice verità è che diventa scomodo esprimere una lingua in modo saggio in grammatiche libere dal contesto che non trattano tutti i suoi dati semplicemente come vettori di bit. I sistemi di tipo statico fanno parte della grammatica della lingua, se ce ne sono, semplicemente la limitano più di quanto potrebbe fare una grammatica libera dal contesto, quindi i controlli grammaticali avvengono in due passaggi sulla fonte. I tipi statici corrispondono alla nozione matematica della teoria dei tipi, la teoria dei tipi in matematica limita semplicemente la legalità di alcune espressioni. Come, non posso dire 3 + [4,7]
in matematica, questo è dovuto alla sua teoria dei tipi.
I tipi statici non sono quindi un modo per "prevenire errori" dal punto di vista teorico, sono una limitazione della grammatica. Infatti, purché +, 3 e gli intervalli abbiano le solite definizioni teoriche impostate, se rimuoviamo il sistema dei tipi 3 + [4,7]
ha un risultato abbastanza ben definito che è un insieme. teoricamente non esistono "errori di runtime", l'uso pratico del sistema dei tipi è di prevenire operazioni che per gli esseri umani non avrebbero alcun senso. Le operazioni sono ancora solo lo spostamento e la manipolazione di bit, ovviamente.
Il problema è che un sistema di tipo non è in grado di decidere se tali operazioni si verificheranno o meno se ne sarebbe consentito l'esecuzione. Come in, esattamente partizionare l'insieme di tutti i programmi possibili in quelli che avranno un 'errore di tipo' e quelli che non lo sono. Può fare solo due cose:
1: prova che si verificheranno errori di tipo in un programma
2: prova che non si verificheranno in un programma
Potrebbe sembrare che mi stia contraddicendo. Ma quello che fa un verificatore di tipo C o Java rifiuta un programma come "non grammaticale", o come lo chiama "errore di tipo" se non riesce a 2. Non può provare che non si verificherà, ciò non significa che non si verificheranno, significa solo che non può provarlo. Potrebbe benissimo essere che un programma che non avrà un errore di tipo venga rifiutato semplicemente perché non può essere provato dal compilatore. Un semplice esempioif(1) a = 3; else a = "string";
, sicuramente poiché è sempre vero, il ramo else non verrà mai eseguito nel programma e non si verificherà alcun errore di tipo. Ma non può dimostrare questi casi in modo generale, quindi viene respinto. Questa è la principale debolezza di molte lingue tipicamente statiche, nel proteggerti da te stesso, sei necessariamente anche protetto nei casi in cui non ne hai bisogno.
Ma, contrariamente alla credenza popolare, ci sono anche linguaggi tipicamente statici che funzionano secondo il principio 1. Rifiutano semplicemente tutti i programmi di cui possono provare che provocherà un errore di tipo e passano tutti i programmi di cui non possono. Quindi è possibile che consentano programmi che presentano errori di battitura, un buon esempio è Typed Racket, è ibrido tra la tipizzazione dinamica e statica. E alcuni direbbero che in questo sistema ottieni il meglio da entrambi i mondi.
Un altro vantaggio della tipizzazione statica è che i tipi sono noti al momento della compilazione, e quindi il compilatore può usarlo. Se in Java facciamo "string" + "string"
o 3 + 3
, entrambi i +
token nel testo alla fine rappresentano un'operazione e un dato completamente diversi, il compilatore sa quale scegliere tra i soli tipi.
Ora farò una dichiarazione molto controversa qui, ma sopporterò con me: la "digitazione dinamica" non esiste .
Sembra molto controverso, ma è vero, i linguaggi tipizzati in modo dinamico sono da una prospettiva teorica non tipizzata . Sono solo lingue tipicamente statiche con un solo tipo. O semplicemente, sono lingue che sono effettivamente generate grammaticalmente da una grammatica libera dal contesto in pratica.
Perché non hanno tipi? Poiché ogni operazione è definita e consentita su ogni operatore, cos'è esattamente un "errore di tipo runtime"? È da un esempio teorico puramente un effetto collaterale . Se fare ciò print("string")
che stampa una stringa è un'operazione, allora lo è anche length(3)
, il primo ha l'effetto collaterale di scrivere string
sull'output standard, il secondo semplicemente error: function 'length' expects array as argument.
, tutto qui. Dal punto di vista teorico non esiste un linguaggio tipizzato dinamicamente. Sono non tipizzati
Va bene, l'ovvio vantaggio del linguaggio "tipizzato in modo dinamico" è il potere espressivo, un sistema di tipi non è altro che una limitazione del potere espressivo. E in generale, le lingue con un sistema di tipi avrebbero effettivamente un risultato definito per tutte quelle operazioni che non sono consentite se il sistema di tipi fosse semplicemente ignorato, i risultati non avrebbero senso per gli umani. Molte lingue perdono la completezza di Turing dopo aver applicato un sistema di tipi.
L'ovvio svantaggio è il fatto che possono verificarsi operazioni che potrebbero produrre risultati insensati per l'uomo. Per evitare ciò, i linguaggi tipizzati dinamicamente in genere ridefiniscono quelle operazioni, piuttosto che produrre quel risultato senza senso lo ridefiniscono per avere l'effetto collaterale di scrivere un errore e possibilmente arrestare del tutto il programma. Questo non è affatto un "errore", infatti, la specifica del linguaggio di solito implica questo, si tratta di un comportamento tanto del linguaggio quanto della stampa di una stringa da una prospettiva teorica. I sistemi di tipo costringono quindi il programmatore a ragionare sul flusso del codice per assicurarsi che ciò non accada. O addirittura, la ragione in modo che esso faAccadere può anche essere utile in alcuni punti per il debug, dimostrando che non è affatto un "errore" ma una proprietà ben definita della lingua. In effetti, l'unico residuo della "tipizzazione dinamica" che la maggior parte delle lingue ha è a guardia di una divisione per zero. Questo è ciò che è la tipizzazione dinamica, non ci sono tipi, non ci sono più tipi di quello zero è un tipo diverso rispetto a tutti gli altri numeri. Quello che la gente chiama un 'tipo' è solo un'altra proprietà di un dato, come la lunghezza di un array, o il primo carattere di una stringa. E molte lingue tipizzate dinamicamente ti permettono anche di scrivere cose come "error: the first character of this string should be a 'z'"
.
Un'altra cosa è che le lingue tipizzate dinamicamente hanno il tipo disponibile in fase di esecuzione e di solito possono verificarlo, gestirlo e decidere da esso. Ovviamente, in teoria non è diverso dall'accedere al primo carattere di un array e vedere di cosa si tratta. In effetti, puoi creare la tua C dinamica, basta usare solo un tipo come long long int e usare i suoi primi 8 bit per memorizzare il tuo 'tipo' e scrivere le funzioni di conseguenza che lo controllano ed eseguono il float o l'aggiunta di numeri interi. Hai una lingua tipicamente statica con un tipo o una lingua dinamica.
In pratica tutto ciò mostra che i linguaggi tipizzati staticamente sono generalmente utilizzati nel contesto della scrittura di software commerciale, mentre i linguaggi tipizzati dinamicamente tendono ad essere utilizzati nel contesto della risoluzione di alcuni problemi e dell'automazione di alcune attività. Scrivere codice in lingue tipicamente statiche richiede semplicemente molto tempo ed è ingombrante perché non puoi fare cose che sai andranno bene, ma il sistema dei tipi ti protegge ancora da te stesso per gli errori che non commetti. Molti programmatori non si rendono nemmeno conto che lo fanno perché è nel loro sistema ma quando si codifica in linguaggi statici, spesso si aggira il fatto che il sistema di tipi non ti consente di fare cose che non possono andare storte, perché non posso provare che non andrà storto.
Come ho notato, "tipizzato staticamente" in generale significa caso 2, colpevole fino a prova contraria. Ma alcuni linguaggi, che non derivano affatto il loro sistema di tipi dalla teoria dei tipi, usano la regola 1: innocente fino a prova contraria, che potrebbe essere l'ibrido ideale. Quindi, forse Typed Racket è per te.
Inoltre, per un esempio più assurdo ed estremo, sto attualmente implementando un linguaggio in cui "tipi" sono veramente il primo carattere di un array, sono dati, dati di "tipo", "tipo", che è esso stesso un tipo e un dato, l'unico dato che ha se stesso come tipo. I tipi non sono limitati o limitati staticamente ma è possibile generare nuovi tipi in base alle informazioni di runtime.
Forse il più grande "vantaggio" della tipizzazione dinamica è la curva di apprendimento più superficiale. Non esiste un sistema di tipi da imparare e nessuna sintassi non banale per casi angolari come i vincoli di tipo. Ciò rende la digitazione dinamica accessibile a molte più persone e fattibile per molte persone per le quali sofisticati sistemi di tipo statico sono fuori portata. Di conseguenza, la tipizzazione dinamica ha preso piede nei contesti dell'educazione (ad esempio Scheme / Python presso il MIT) e nei linguaggi specifici del dominio per i non programmatori (ad esempio Mathematica ). I linguaggi dinamici hanno anche preso piede nelle nicchie in cui hanno poca o nessuna concorrenza (ad esempio Javascript).
I linguaggi tipizzati dinamicamente più concisi (ad esempio Perl, APL, J, K, Mathematica ) sono specifici del dominio e possono essere significativamente più concisi dei linguaggi tipicamente statici di uso generale più concisi (ad esempio OCaml ) nelle nicchie per cui sono stati progettati .
I principali svantaggi della tipizzazione dinamica sono:
Errori di tipo runtime.
Può essere molto difficile o addirittura praticamente impossibile raggiungere lo stesso livello di correttezza e richiede molti più test.
Nessuna documentazione verificata dal compilatore.
Scarse prestazioni (di solito in fase di esecuzione ma a volte in fase di compilazione, ad esempio Stalin Scheme) e prestazioni imprevedibili a causa della dipendenza da sofisticate ottimizzazioni.
Personalmente, sono cresciuto con linguaggi dinamici ma non li toccherei con un palo da 40 'come professionista se non ci fossero altre opzioni praticabili.
Dall'articolo di Artima : Strong vs. Weak, Statico vs. Dynamic articolo:
la tipizzazione forte impedisce operazioni di miscelazione tra tipi non corrispondenti. Per mescolare i tipi, è necessario utilizzare una conversione esplicita
la digitazione debole significa che puoi mescolare i tipi senza una conversione esplicita
Nel documento di Pascal Costanza, La tipizzazione dinamica vs. statica - Un'analisi basata su pattern (PDF), afferma che in alcuni casi, la tipizzazione statica è più soggetta a errori rispetto alla tipizzazione dinamica. Alcune lingue tipizzate staticamente ti costringono ad emulare manualmente la digitazione dinamica per fare "La cosa giusta". È discusso in Lambda the Ultimate .
Dipende dal contesto. Ci sono molti vantaggi che sono appropriati per il sistema tipizzato dinamico e anche per quello tipizzato forte. Sono dell'opinione che il flusso del linguaggio dei tipi dinamici sia più veloce. I linguaggi dinamici non sono vincolati agli attributi di classe e al compilatore che pensa a cosa sta succedendo nel codice. Hai un po 'di libertà. Inoltre, il linguaggio dinamico di solito è più espressivo e produce meno codice, il che è positivo. Nonostante ciò, è più soggetto a errori che è anche discutibile e dipende maggiormente dalla copertura dei test unitari. È un prototipo semplice con un linguaggio dinamico ma la manutenzione può diventare un incubo.
Il principale vantaggio rispetto al sistema tipizzato statico è il supporto IDE e sicuramente un analizzatore statico di codice. Diventa più sicuro del codice dopo ogni modifica del codice. La manutenzione è un gioco da ragazzi con tali strumenti.
Ci sono molte cose diverse sui linguaggi statici e dinamici. Per me, la differenza principale è che nei linguaggi dinamici le variabili non hanno tipi fissi; invece, i tipi sono legati ai valori. Per questo motivo, il codice esatto che viene eseguito è indeterminato fino al runtime.
Nelle prime o ingenui implementazioni questa è un'enorme riduzione delle prestazioni, ma i moderni JIT si avvicinano in modo allettante al meglio che puoi ottenere con l'ottimizzazione dei compilatori statici. (in alcuni casi marginali, anche meglio di così).
Si tratta dello strumento giusto per il lavoro. Né è meglio il 100% delle volte. Entrambi i sistemi sono stati creati dall'uomo e presentano difetti. Scusa, ma facciamo schifo e realizziamo cose perfette.
Mi piace la digitazione dinamica perché mi impedisce, ma sì, gli errori di runtime possono insinuarsi che non avevo pianificato. Laddove la digitazione statica può correggere gli errori di cui sopra, ma fa impazzire un programmatore principiante (in lingue tipizzate) cercando di lanciare tra un carattere costante e una stringa.
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