Digitazione graduale: "Quasi ogni lingua con un sistema di tipo statico ha anche un sistema di tipo dinamico"


20

Questa affermazione di Aleks Bromfield afferma:

Quasi ogni lingua con un sistema di tipo statico ha anche un sistema di tipo dinamico. A parte C, non riesco a pensare a un'eccezione

È un reclamo valido? Capisco che con Reflection o Loading classi in fase di runtime Java diventa un po 'così - ma questa idea di "digitazione graduale" può essere estesa a un gran numero di lingue?


Non sono un esperto di lingue, ma alcuni che mi vengono subito in mente che non credo abbiano tipi dinamici (nativamente, non dicendo che non potresti mettere insieme qualcosa in questi) - Fortran, Ada, Pascal, Cobol
mattnz

4
Sono un esperto di lingue e non sono sicuro di cosa stia sostenendo questo ragazzo. "statico" e "dinamico" sono termini impropri e di solito indicano l'ora del controllo / analisi del tipo (sia in fase di compilazione che in fase di esecuzione). Alcuni linguaggi conciliano entrambi (ad es. Impedendo operazioni su tipi non supportati durante la compilazione e sollevando eccezioni come ClassCastException durante il runtime), e questo potrebbe essere ciò che intende. In tal caso, è vero che C di solito non esegue il controllo del tipo durante il runtime. Dire una lingua. non ha "sistema di tipo dinamico" non ha senso.
Thiago Silva,

Risposte:


37

Tweeter originale qui. :)

Prima di tutto, sono un po 'divertito / scioccato dal fatto che il mio tweet sia preso così sul serio! Se avessi saputo che sarebbe stato così ampiamente diffuso, avrei trascorso più di 30 secondi a scriverlo!

Thiago Silva ha giustamente sottolineato che "statico" e "dinamico" descrivono più accuratamente il controllo del tipo , piuttosto che i sistemi di tipo . In effetti, non è proprio esatto affermare che una lingua sia tipizzata staticamente o dinamicamente. Piuttosto, una lingua ha un sistema di tipi e un'implementazione di quella lingua potrebbe imporre il sistema di tipi usando il controllo statico, il controllo dinamico, o entrambi, o nessuno dei due (anche se non sarebbe un'implementazione del linguaggio molto accattivante!).

In effetti, ci sono alcuni sistemi di tipo (o caratteristiche dei sistemi di tipo) che sono più suscettibili al controllo statico e ci sono alcuni sistemi di tipo (o caratteristiche dei sistemi di tipo) che sono più suscettibili al controllo dinamico. Ad esempio, se la tua lingua ti consente di specificare nel testo di un programma che un determinato valore deve sempre essere un array di numeri interi, allora è ragionevolmente semplice scrivere un controllo statico per verificare quella proprietà. Al contrario, se la tua lingua ha un sottotitolo e se consente il downcasting, è ragionevolmente semplice verificare la validità di un downcast in fase di esecuzione, ma è estremamente difficile farlo al momento della compilazione.

Quello che intendevo veramente con il mio tweet è semplicemente che la stragrande maggioranza delle implementazioni linguistiche esegue un certo controllo dinamico del tipo. O, equivalentemente, la stragrande maggioranza delle lingue ha alcune caratteristiche che sono difficili (se non impossibili) da controllare staticamente. Il downcasting è un esempio. Altri esempi includono overflow aritmetico, controllo dei limiti dell'array e controllo null. Alcuni di questi possono essere controllati staticamente in alcune circostanze, ma nel complesso, sarebbe difficile trovare un'implementazione del linguaggio che non esegua alcun controllo in fase di esecuzione.

Questa non è una brutta cosa. È solo un'osservazione che ci sono molte proprietà interessanti che vorremmo far applicare alle nostre lingue e che non sappiamo davvero come controllare staticamente. Ed è un promemoria che distinzioni come "tipi statici" rispetto a "tipi dinamici" non sono così nette come alcune persone vorrebbero farti credere. :)

Un'ultima nota: i termini "forte" e "debole" non sono realmente utilizzati nella comunità di ricerca del linguaggio di programmazione e non hanno un significato coerente. In generale, ho scoperto che quando qualcuno dice che una lingua ha "digitazione forte" e un'altra lingua ha "digitazione debole", stanno davvero dicendo che la loro lingua preferita (quella con "digitazione forte") impedisce loro di commettendo un errore che l'altra lingua (quella con "digitazione debole") non - o viceversa, che la loro lingua preferita (quella con "digitazione debole") consente loro di fare qualcosa di interessante che l'altra lingua (il uno con "digitazione forte") no.


9
"È solo un'osservazione che ci sono molte proprietà interessanti che vorremmo far applicare alle nostre lingue e che non sappiamo davvero come controllare staticamente." - Beh, non è solo che non sappiamo come farlo. "Questo arresto del programma per questo ingresso" è una proprietà interessante che non solo non sappiamo come controllare, ma in realtà ci fanno sapere è impossibile da controllare.
Jörg W Mittag,

"Altri esempi includono overflow aritmetico, controllo dei limiti di array e controllo null." Solo una nota che mentre ci sono alcune lingue che controllano queste proprietà nel sistema dei tipi, anche nella maggior parte delle lingue tipizzate dinamicamente queste sono di solito una caratteristica dei valori , non dei tipi. (Il controllo "Null" è una caratteristica comune dei sistemi di tipo statico.)
porglezomp

V'è un tipo di dinamica del sistema , e di un tipo statico del sistema . Anche se nessuno dei due viene applicato, sono ancora lì, descrivendo ciò che è corretto e ciò che è un errore. La lingua / implementazione può controllare o meno uno di essi. A proposito, il sistema di tipo statico e dinamico dovrebbe essere coerente, ma non è il caso per definizione .
Elazar,

Ogni lingua ha un sistema di tipi dinamico, che è un insieme di regole che vietano l'esecuzione di determinate operazioni.
Elazar,

7

Beh si. Puoi avere borse di proprietà in qualsiasi lingua tipizzata staticamente. La sintassi sarà terribile mentre allo stesso tempo otterrai tutti gli svantaggi del sistema tipizzato dinamicamente. Quindi non c'è davvero alcun vantaggio a meno che il compilatore non ti permetta di usare una sintassi migliore, come dynamicsta facendo C # .

Inoltre, puoi farlo abbastanza facilmente anche in C.

In risposta ad altre risposte: penso che le persone stiano confondendo la digitazione statica / dinamica con la digitazione forte / debole. La tipizzazione dinamica riguarda la possibilità di modificare la struttura dei dati in fase di runtime e il codice di poter utilizzare i dati che si adattano solo alle esigenze del codice. Questo si chiama Duck Typing .

Menzionare la riflessione non sta raccontando l'intera storia, perché la riflessione non consente di modificare la struttura esistente dei dati. Non è possibile aggiungere un nuovo campo a una classe o struttura in C, C ++, Java o C #. Nei linguaggi dinamici, l'aggiunta di nuovi campi o attributi alle classi esistenti non è solo possibile, ma in realtà abbastanza comune.

Ad esempio, guarda Cython , il compilatore da Python a C. Crea codice C statico, ma il sistema di tipi mantiene ancora la sua natura dinamica. C è un linguaggio tipicamente statico, ma è in grado di supportare la tipizzazione dinamica da Python.


Tecnicamente, puoi farlo in C # a partire dalla versione 4 ExpandoObject, anche se è molto un processo di opt-in, molto diverso da JavaScript o Ruby. Tuttavia, hai fatto un punto molto importante, che è che la tipizzazione anatra (cosa significa effettivamente il 99% degli sviluppatori quando dicono "tipizzati dinamicamente") e la riflessione non sono affatto le stesse cose.
Aaronaught il

Potrei anche aggiungere che Python non ha una vera digitazione da anatra. Ha solo dei ganci per "implementare il tuo" (ha un metodo magico che può tornare Trueper dire "questo pazzo oggetto è un'istanza della classe che sto definendo"). OCaml ha questa funzione per quanto ne so, ma non lo so davvero.
vlad-ardelean,

6

Le lingue dinamiche sono lingue statiche . Quello che comunemente viene chiamato "tipizzazione dinamica" è in realtà un caso speciale di tipizzazione statica - il caso in cui ti sei limitato ad avere un solo tipo. Come esperimento mentale, immagina di scrivere un programma in Java o C # usando solo Objectvariabili / campi / parametri e di eseguire il down-casting immediatamente prima di chiamare qualsiasi metodo. Sarebbe più accurato chiamare linguaggi come Python o Javascript "unityped". (Questa affermazione probabilmente confonderà / disturberà molte persone, considerando che un tale programma Java o C # userebbe molti sottotipi, ma questo perché il linguaggio OOP medio comprende tipi e classi. Leggi il post sul blog per maggiori dettagli.)

Nota che anche C ha una digitazione "dinamica": puoi lanciare qualsiasi puntatore su un puntatore void(e se la memoria mi serve char) e viceversa. E nota, inoltre, che non esiste un runtime che controlla lì; se sbagli, goditi il ​​tuo comportamento indefinito!


Ma il cast è fatto staticamente. Non riesco a vedere come questo sia un esempio di digitazione dinamica.
osa,

@osa Solo perché il codice dice String foo = (String) barche non significa che barin realtà sia un String. Lo puoi sapere con certezza solo in fase di esecuzione, quindi non vedo come il cast sia fatto "staticamente".
Doval,

Non sono d'accordo con questo. Almeno in Javascript, è possibile aggiungere nuovi metodi e proprietà agli oggetti in fase di esecuzione. In C #, devi usare esplicitamente un dynamicoggetto per farlo. Se provi ad aggiungere una proprietà a un object... beh, non puoi.
Arturo Torres Sánchez,

3

La differenza tra tipizzazione statica e dinamica è quando viene controllato il tipo di un valore: tempo di compilazione vs. tempo di esecuzione. Nelle lingue in cui i valori portano con sé il loro tipo (ad es. Oggetti Java), puoi sempre ricorrere alla tipizzazione dinamica anche quando la lingua preferisce la tipizzazione statica. Ecco un esempio in Java, con un metodo digitato in modo dinamico:

void horribleJava(List untypedList) {
  for (Object o : untypedList)
    ((SpecificType) o).frobnicate();
}

Notare come viene controllato il tipo di ciascun elemento in fase di esecuzione. Il metodo equivalente digitato staticamente è:

void goodJava(List<SpecificType> typedList) {
  for (SpecificType o : typedList) {
    o.forbnicate();
  }
}

In C, i valori (e in particolare i puntatori) non mantengono il loro tipo durante il runtime - ogni puntatore equivale a void *. Invece, le variabili e le espressioni hanno un tipo. Per ottenere una digitazione dinamica, è necessario portare da sé le informazioni sul tipo (ad es. Come un campo in una struttura).


1
Non credo che un cast valga come una digitazione dinamica in alcun senso davvero pratico. Richiede ancora la conoscenza del tipo in fase di compilazione, difende la convalida effettiva fino al runtime. Non puoi invocare il frobnicatemetodo qui senza prima saperlo SpecificType.
Aaronaught il

2
@Aaronaught Ma questa è una digitazione dinamica una volta che abbiamo differito il controllo del tipo per l'esecuzione. Nota che entrambi i miei esempi usano la digitazione nominativa che richiede un nome di tipo specifico. Stai pensando alla tipizzazione strutturale , ad esempio la tipizzazione anatra che richiede la presenza di un metodo. Gli assi strutturale contro nominativo e statico contro dinamico sono ortogonali tra loro (Java è nominativo e prevalentemente statico; ML e Go sono strutturali e statici; Perl, Python e Ruby sono (principalmente) strutturali e dinamici).
amon,

Come ho detto nel mio ultimo commento, è una distinzione teorica che nessun programmatore che abbia mai incontrato si preoccupi davvero. Puoi argomentare in modo abrasivo che le persone usano una terminologia errata (e in effetti sembra che il tweeter originale stesse andando proprio per quel tipo di snarkiness) ma per le persone che sono effettivamente in trincea, digitando dinamico = digitando anatra. In effetti quella definizione è così comune che lingue come C # l'hanno effettivamente codificata (cioè con la dynamicparola chiave). L'equazione tra statico e tempo di compilazione e dinamica e tempo di esecuzione, per lo più confonde le acque.
Aaronaught il

@Aaronaught: se si esegue il cast su un'interfaccia e se le classi che implementano un metodo con il significato previsto implementano costantemente la stessa interfaccia per dirlo, allora si sarebbe essenzialmente in fase di digitazione in fase di esecuzione. Mentre alcuni potrebbero sostenere che la "tipizzazione anatra" dovrebbe semplicemente usare il nome del metodo, penso che sarebbe più utile considerare il nome del metodo "reale" come il nome dell'interfaccia più il nome del metodo. In caso contrario, dovrebbe [1,2].Add([3,4])cedere [1,2,3,4], [1,2,[3,4]]o [4,6]?
supercat

@supercat: nessuna delle precedenti, dovrebbe fallire perché non esiste un Addmetodo sull'array che accetta un array perché tale metodo sarebbe ambiguo. La digitazione anatra non ti scusa dalla scrittura di tipi e funzioni comprensibili.
Aaronaught,

2

La tipizzazione statica e dinamica si riferisce essenzialmente al modo in cui i tipi vengono controllati. La tipizzazione statica significa che la verifica dei tipi di varie variabili o espressioni viene verificata in base al codice effettivo (solitamente dal compilatore) mentre in un sistema di tipo dinamico questa verifica viene eseguita solo in fase di esecuzione, dall'ambiente di runtime.

Ciò a cui credo si riferisca il testo è che anche se i tipi sono effettivamente controllati staticamente, vengono anche controllati in fase di esecuzione, cioè dinamicamente. Hai citato correttamente Java Reflection; reflection viene eseguito solo in fase di runtime e Java Runtime Environment (JVM) esegue effettivamente il controllo del tipo quando si utilizza il reflection, il che significa sostanzialmente controllo dinamico del tipo.


Quindi non è corretto. In C ++, Pascal, Fortran --- in tutti i linguaggi compilati --- i tipi vengono controllati solo staticamente e non dinamicamente (a meno che non si stia utilizzando dynamic_cast). Puoi usare i puntatori per scrivere cose arbitrarie in memoria e nessuno ne conoscerà i tipi. Quindi la tipizzazione statica significa SOLO CONTROLLO STATICO, mentre la digitazione dinamica significa SOLO CONTROLLO A TEMPO DI FUNZIONAMENTO.
osa,

-1

L'esclusione è sbagliata: C ha anche un importante sistema di tipo dinamico. Semplicemente non lo controlla ("C è fortemente tipizzato, debolmente controllato"). Ad esempio, trattare una struttura come uno double( reinternpret_caststile) produce un comportamento indefinito, un errore di tipo dinamico.


(A chiunque abbia annullato il voto - il commento di @Thiago Silva dice della stessa cosa)
Elazar
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.