Quali funzionalità consente la digitazione dinamica? [chiuso]


91

Sto usando Python da alcuni giorni e penso di capire la differenza tra la tipizzazione dinamica e statica. Quello che non capisco è in quali circostanze sarebbe preferito. È flessibile e leggibile, ma a spese di ulteriori controlli di runtime e test di unità aggiuntivi richiesti.

A parte criteri non funzionali come la flessibilità e la leggibilità, quali sono le ragioni per scegliere la tipizzazione dinamica? Cosa posso fare con la digitazione dinamica che altrimenti non è possibile? Quale esempio di codice specifico puoi pensare che illustri un vantaggio concreto della digitazione dinamica?


5
Teoricamente non c'è niente che tu non possa fare, a condizione che le lingue siano Turing Complete . La domanda più interessante per me è cosa sia facile o naturale nell'uno rispetto all'altro. Ci sono cose che faccio regolarmente in Python che non prenderei nemmeno in considerazione in C ++ anche se so che è capace.
Mark Ransom,

28
Come scrive Chris Smith nel suo eccellente saggio Cosa sapere prima di discutere dei sistemi di tipo : "Il problema, in questo caso, è che la maggior parte dei programmatori ha un'esperienza limitata e non ha provato molte lingue. Per il contesto, qui, sei o sette non conta come "molto" ... Due conseguenze interessanti di ciò sono: (1) Molti programmatori hanno usato linguaggi tipicamente statici molto poveri. (2) Molti programmatori hanno usato linguaggi tipizzati dinamicamente molto male. "
Daniel Pryden,

3
@suslik: se i primitivi del linguaggio hanno tipi senza senso, ovviamente puoi fare cose senza senso con i tipi. Ciò non ha nulla a che fare con la differenza tra la tipizzazione statica e dinamica.
Jon Purdy,

10
@CzarekTomczak: questa è una caratteristica di alcune lingue tipizzate dinamicamente, sì. Ma è possibile che un linguaggio tipizzato staticamente sia modificabile in fase di esecuzione. Ad esempio, Visual Studio consente di riscrivere il codice C # mentre ci si trova in un punto di interruzione nel debugger e persino di riavvolgere il puntatore dell'istruzione per rieseguire il codice con nuove modifiche. Come ho citato Chris Smith nel mio altro commento: "Molti programmatori hanno usato linguaggi tipicamente statici molto poveri" - non giudicare tutti i linguaggi tipicamente statici da quelli che conosci.
Daniel Pryden,

11
@WarrenP: Affermi che "i sistemi di tipo dinamico riducono la quantità di extra cruft che devo digitare" - ma poi confronti Python con C ++. Questo non è un paragone equo: ovviamente C ++ è più dettagliato di Python, ma non è per via della differenza nei loro sistemi di tipi, è per via della differenza nelle loro grammatiche. Se vuoi solo ridurre il numero di caratteri nella fonte del tuo programma, impara J o APL: ti garantisco che saranno più brevi. Un confronto più equo sarebbe confrontare Python con Haskell. (Per la cronaca: adoro Python e lo preferisco al C ++, ma Haskell mi piace ancora di più.)
Daniel Pryden,

Risposte:


50

Dato che hai chiesto un esempio specifico, te ne darò uno.

Il massiccio ORM di Rob Conery è composto da 400 righe di codice. È così piccolo perché Rob è in grado di mappare le tabelle SQL e fornire risultati degli oggetti senza richiedere molti tipi statici per il mirroring delle tabelle SQL. Ciò si ottiene utilizzando il dynamictipo di dati in C #. La pagina Web di Rob descrive questo processo in dettaglio, ma sembra chiaro che, in questo particolare caso d'uso, la tipizzazione dinamica è in gran parte responsabile della brevità del codice.

Confronta con Sam Saffron's Dapper , che utilizza tipi statici; la SQLMappersola classe è di 3000 righe di codice.

Si noti che si applicano le solite dichiarazioni di non responsabilità e il chilometraggio può variare; Dapper ha obiettivi diversi rispetto a Massive. Lo faccio solo notare come un esempio di qualcosa che puoi fare in 400 righe di codice che probabilmente non sarebbe possibile senza la digitazione dinamica.


La digitazione dinamica ti consente di rinviare le tue decisioni di tipo al runtime. È tutto.

Sia che tu utilizzi un linguaggio tipizzato in modo dinamico o uno scritto in modo statico, le tue scelte di tipo devono essere comunque sensate. Non aggiungerai due stringhe insieme e ti aspetterai una risposta numerica a meno che le stringhe non contengano dati numerici e, in caso contrario, otterrai risultati imprevisti. Una lingua tipicamente statica non ti permetterà di farlo in primo luogo.

I sostenitori di linguaggi di tipo statico sottolineano che il compilatore può eseguire una notevole quantità di "controllo di integrità" del codice al momento della compilazione, prima dell'esecuzione di una singola riga. Questa è una buona cosa ™.

C # ha la dynamicparola chiave, che consente di rinviare la decisione del tipo al runtime senza perdere i benefici della sicurezza del tipo statico nel resto del codice. Type Inference ( var) elimina gran parte del dolore della scrittura in un linguaggio tipicamente statico, eliminando la necessità di dichiarare sempre esplicitamente i tipi.


I linguaggi dinamici sembrano favorire un approccio più interattivo e immediato alla programmazione. Nessuno si aspetta che tu debba scrivere una classe e passare attraverso un ciclo di compilazione per digitare un po 'di codice Lisp e vederlo eseguire. Eppure è esattamente quello che mi aspetto di fare in C #.


22
Se avessi aggiunto due stringhe numeriche insieme, non mi sarei aspettato un risultato numerico.
pdr,

22
@Robert Sono d'accordo con la maggior parte della tua risposta. Tuttavia, si noti che esistono linguaggi tipicamente statici con loop interattivi di lettura-valutazione, come Scala e Haskell. È possibile che C # non sia un linguaggio particolarmente interattivo.
Andres F.

14
Devo imparare un Haskell.
Robert Harvey,

7
@RobertHarvey: potresti essere sorpreso / impressionato con F # se non l'hai già provato. Ottieni tutta la sicurezza del tipo (in fase di compilazione) che normalmente ottieni in un linguaggio .NET, tranne per il fatto che raramente devi dichiarare alcun tipo. L'inferenza del tipo in F # va oltre ciò che è disponibile / funziona in C #. Inoltre: simile a quello che sottolinea Andres e Daniel, F # interactive fa parte di Visual Studio ...
Steven Evers,

8
"Non hai intenzione di aggiungere due stringhe insieme e ti aspetti una risposta numerica a meno che le stringhe non contengano dati numerici e, in caso contrario, otterrai risultati imprevisti" scusa, non ha nulla a che fare con la digitazione dinamica vs statica , si tratta di una digitazione forte o debole .
vartec,

26

Frasi come "tipizzazione statica" e "tipizzazione dinamica" sono molto diffuse e le persone tendono ad usare definizioni leggermente diverse, quindi iniziamo chiarendo cosa intendiamo.

Prendi in considerazione un linguaggio con tipi statici che vengono controllati in fase di compilazione. Ma supponiamo che un errore di tipo generi solo un avviso non fatale e, in fase di esecuzione, tutto è tipizzato a forma di anatra. Questi tipi statici sono solo per comodità del programmatore e non influiscono sul codegen. Ciò dimostra che la tipizzazione statica non impone di per sé alcuna limitazione e non si esclude a vicenda con la tipizzazione dinamica. (Objective-C è molto simile a questo.)

Ma la maggior parte dei sistemi di tipo statico non si comporta in questo modo. Esistono due proprietà comuni dei sistemi di tipo statico che possono imporre limitazioni:

Il compilatore potrebbe rifiutare un programma che contiene un errore di tipo statico.

Questa è una limitazione perché molti programmi sicuri di tipo contengono necessariamente un errore di tipo statico.

Ad esempio, ho uno script Python che deve essere eseguito come Python 2 e Python 3. Alcune funzioni hanno cambiato il tipo di parametro tra Python 2 e 3, quindi ho un codice come questo:

if sys.version_info[0] == 2:
    wfile.write(txt)
else:
    wfile.write(bytes(txt, 'utf-8'))

Un correttore di tipo statico Python 2 rifiuterebbe il codice Python 3 (e viceversa), anche se non sarebbe mai stato eseguito. Il mio programma di tipo sicuro contiene un errore di tipo statico.

Come altro esempio, considera un programma per Mac che vuole essere eseguito su OS X 10.6, ma sfrutta le nuove funzionalità di 10.7. I metodi 10.7 possono esistere o meno in fase di esecuzione ed è compito mio, il programmatore, rilevarli. Un verificatore di tipo statico è costretto a rifiutare il mio programma per garantire la sicurezza del tipo o ad accettarlo, insieme alla possibilità di produrre un errore di tipo (funzione mancante) in fase di esecuzione.

Il controllo statico del tipo presuppone che l'ambiente di runtime sia adeguatamente descritto dalle informazioni sul tempo di compilazione. Ma prevedere il futuro è pericoloso!

Ecco un'altra limitazione:

Il compilatore può generare codice che presuppone che il tipo di runtime sia di tipo statico.

Supponendo che i tipi statici siano "corretti" offre molte opportunità di ottimizzazione, ma queste ottimizzazioni possono essere limitanti. Un buon esempio sono gli oggetti proxy, ad esempio i telecomandi. Supponi di voler avere un oggetto proxy locale che inoltri le invocazioni di metodo a un oggetto reale in un altro processo. Sarebbe bello se il proxy fosse generico (quindi può mascherarsi come qualsiasi oggetto) e trasparente (in modo che il codice esistente non abbia bisogno di sapere che sta parlando con un proxy). Ma per fare ciò, il compilatore non può generare codice che presume che i tipi statici siano corretti, ad es. Facendo riferimento alle chiamate dei metodi in modo statico, poiché ciò non riuscirà se l'oggetto è effettivamente un proxy.

Esempi di tale remoting in azione includono NSXPCConnection di ObjC o TransparentProxy di C # (la cui implementazione ha richiesto alcune pessimizzazioni in fase di esecuzione - vedi qui per una discussione).

Quando il codegen non dipende dai tipi statici e hai servizi come l'inoltro dei messaggi, puoi fare un sacco di cose interessanti con oggetti proxy, debug, ecc.

Quindi questo è un campione di alcune delle cose che puoi fare se non sei tenuto a soddisfare un controllo di tipo. Le limitazioni non sono imposte dai tipi statici, ma dal controllo del tipo statico forzato.


2
"Un correttore di tipo statico Python 2 rifiuterebbe il codice Python 3 (e viceversa), anche se non sarebbe mai stato eseguito. Il mio programma di tipo sicuro contiene un errore di tipo statico." Sembra che ciò di cui hai davvero bisogno ci sia una sorta di "static if", in cui il compilatore / interprete non vede nemmeno il codice se la condizione è falsa.
David Stone,

@davidstone che esiste in c ++
Milind R

A Python 2 static type checker would reject the Python 3 code (and vice versa), even though it would never be executed. My type safe program contains a static type error. In qualsiasi linguaggio statico ragionevole, è possibile farlo con un'istruzione di IFDEFtipo preprocessore, mantenendo la sicurezza del tipo in entrambi i casi.
Mason Wheeler,

1
@MasonWheeler, davidstone No, i trucchi del preprocessore e static_if sono entrambi troppo statici. Nel mio esempio ho usato Python2 e Python3, ma avrebbe potuto facilmente essere AmazingModule2.0 e AmazingModule3.0, in cui alcune interfacce cambiavano tra le versioni. Il primo che puoi conoscere l'interfaccia è al momento dell'importazione del modulo, che è necessariamente in fase di esecuzione (almeno se hai qualche desiderio di supportare il collegamento dinamico).
ridiculous_fish

18

Le variabili tipizzate con anatra sono la prima cosa a cui tutti pensano, ma nella maggior parte dei casi puoi ottenere gli stessi benefici attraverso l'inferenza di tipo statico.

Ma la digitazione di anatre in collezioni create dinamicamente è difficile da ottenere in qualsiasi altro modo:

>>> d = JSON.parse(foo)
>>> d['bar'][3]
12
>>> d['baz']['qux']
'quux'

Quindi, che tipo JSON.parserestituisce? Un dizionario di matrici di numeri interi o dizionari di stringhe? No, anche quello non è abbastanza generale.

JSON.parsedeve restituire una sorta di "valore variante" che può essere null, bool, float, string, array di uno di questi tipi ricorsivamente o dizionario da stringa a uno qualsiasi di questi tipi ricorsivamente. I principali punti di forza della tipizzazione dinamica derivano dall'avere tali tipi di varianti.

Finora, questo è un vantaggio di tipi dinamici , non di linguaggi tipizzati dinamicamente. Un linguaggio statico decente può simulare perfettamente qualsiasi tipo di questo tipo. (E anche le lingue "cattive" possono spesso simularle rompendo la sicurezza del tipo sotto il cofano e / o richiedendo una sintassi di accesso maldestra.)

Il vantaggio dei linguaggi tipizzati dinamicamente è che tali tipi non possono essere dedotti da sistemi di inferenza di tipo statico. Devi scrivere il tipo in modo esplicito. Ma in molti casi simili, incluso questo una volta, il codice per descrivere il tipo è esattamente complicato come il codice per analizzare / costruire gli oggetti senza descriverne il tipo, quindi non è necessariamente un vantaggio.


21
L'esempio di analisi JSON può essere facilmente gestito staticamente da un tipo di dati algebrico.

2
OK, la mia risposta non era abbastanza chiara; Grazie. Che JSValue sia una definizione esplicita di un tipo dinamico, esattamente di cosa stavo parlando. Sono quei tipi dinamici che sono utili, non le lingue che richiedono la digitazione dinamica. Tuttavia, è ancora rilevante che i tipi dinamici non possano essere generati automaticamente da nessun sistema di inferenza di tipo reale, mentre la maggior parte degli esempi comuni che le persone sono banalmente inferibili. Spero che la nuova versione lo spieghi meglio.
abarnert,

4
I tipi di dati algebrici di @MattFenwick sono praticamente limitati ai linguaggi funzionali (in pratica). Che dire di lingue come Java e c #?
spirc,

4
Gli ADT esistono in C / C ++ come sindacati con tag. Questo non è unico per i linguaggi funzionali.
Clark Gaebel,

2
@spirc è possibile emulare gli ADT in un linguaggio OO classico utilizzando più classi che derivano tutte da un'interfaccia comune, chiamate di runtime a getClass () o GetType () e controlli di uguaglianza. Oppure puoi usare il doppio dispacciamento, ma penso che ripaga di più in C ++. Quindi potresti avere un'interfaccia JSObject e le classi JSString, JSNumber, JSHash e JSArray. Avresti quindi bisogno di un po 'di codice per trasformare questa struttura di dati "non tipizzata" in una struttura di dati "tipizzata dall'applicazione". Ma probabilmente vorrai farlo anche in un linguaggio tipizzato in modo dinamico.
Daniel Yankowsky,

12

Poiché ogni sistema di tipo statico a distanza pratico è fortemente limitato rispetto al linguaggio di programmazione di cui si occupa, non può esprimere tutti gli invarianti che il codice potrebbe verificare in fase di esecuzione. Al fine di non eludere le garanzie che un sistema di tipo tenta di offrire, opta quindi per essere conservativo e non consentire l'uso di casi che supererebbero questi controlli, ma che non è possibile dimostrare (nel sistema di tipo).

Farò un esempio. Supponiamo di implementare un semplice modello di dati per descrivere oggetti di dati, raccolte di essi, ecc. Che sia staticamente tipizzato, nel senso che, se il modello dice che l'attributo xdi oggetto di tipo Foo contiene un numero intero, deve sempre contenere un numero intero. Poiché si tratta di un costrutto di runtime, non è possibile digitarlo staticamente. Supponiamo di memorizzare i dati descritti nei file YAML. Crei una mappa hash (da consegnare a una libreria YAML in un secondo momento), ottieni l' xattributo, memorizzalo nella mappa, ottieni quell'altro attributo che in realtà è una stringa, ... tieni un secondo? Di che tipo è the_map[some_key]adesso? Bene, sappiamo che lo some_keyè 'x'e il risultato quindi deve essere un numero intero, ma il sistema di tipi non può nemmeno iniziare a ragionare su questo.

Alcuni sistemi di tipi ricercati attivamente possono funzionare per questo esempio specifico, ma questi sono estremamente complicati (sia per gli autori di compilatori da implementare sia per il programmatore in cui ragionare), specialmente per qualcosa di così "semplice" (voglio dire, l'ho appena spiegato in uno paragrafo).

Ovviamente, la soluzione di oggi è inscatolare tutto e poi lanciare (o avere un sacco di metodi di sostituzione, la maggior parte dei quali solleva eccezioni "non implementate"). Ma questo non è tipicamente statico, è un trucco attorno al sistema dei tipi per eseguire i controlli dei tipi in fase di esecuzione.


I tipi generici non hanno il requisito di boxe.
Robert Harvey,

@RobertHarvey Sì. Non stavo parlando con la boxe in Java C #, stavo parlando di "concluderlo in una classe wrapper il cui unico scopo è rappresentare un valore di T in un sottotipo di U". Il polimorfismo parametrico (ciò che chiami tipizzazione generica) tuttavia non si applica al mio esempio. È un'astrazione in fase di compilazione rispetto ai tipi concreti, ma è necessario un meccanismo di digitazione in fase di esecuzione.

Potrebbe valere la pena sottolineare che il sistema di tipi di Scala è Turing completo. Quindi i sistemi di tipi possono essere meno banali di quanto immagini.
Andrea,

@Andrea Non ho intenzionalmente ridotto la mia descrizione a completezza turing. Mai programmato in un tarpit turing? O hai provato a codificare queste cose in tipi? Ad un certo punto, diventa troppo complicato per essere fattibile.

@delnan Sono d'accordo. Stavo solo sottolineando che i sistemi di tipo possono fare cose abbastanza complicate. Ho avuto l'impressione che la tua risposta significasse che il sistema dei tipi può fare solo una banale verifica, ma in una seconda lettura non hai scritto niente del genere!
Andrea,

7

Non c'è niente che tu possa fare con la tipizzazione dinamica che non puoi fare con la tipizzazione statica, perché puoi implementare la tipizzazione dinamica su un linguaggio tipizzato staticamente.

Un breve esempio in Haskell:

data Data = DString String | DInt Int | DDouble Double

-- defining a '+' operator here, with explicit promotion behavior
DString a + DString b = DString (a ++ b)
DString a + DInt b = DString (a ++ show b)
DString a + DDouble b = DString (a ++ show b)
DInt a + DString b = DString (show a ++ b)
DInt a + DInt b = DInt (a + b)
DInt a + DDouble b = DDouble (fromIntegral a + b)
DDouble a + DString b = DString (show a ++ b)
DDouble a + DInt b = DDouble (a + fromIntegral b)
DDouble a + DDouble b = DDouble (a + b)

Con un numero sufficiente di casi è possibile implementare qualsiasi dato sistema di tipo dinamico.

Viceversa, puoi anche tradurre qualsiasi programma tipicamente statico in uno equivalente dinamico. Naturalmente, perdereste tutte le garanzie di correttezza in fase di compilazione fornite dal linguaggio tipizzato staticamente.

Modifica: volevo mantenerlo semplice, ma qui ci sono più dettagli su un modello a oggetti

Una funzione prende un elenco di dati come argomenti ed esegue calcoli con effetti collaterali in ImplMonad e restituisce un dato.

type Function = [Data] -> ImplMonad Data

DMember è un valore membro o una funzione.

data DMember = DMemValue Data | DMemFunction Function

Estendi Dataper includere oggetti e funzioni. Gli oggetti sono elenchi di membri nominati.

data Data = .... | DObject [(String, DMember)] | DFunction Function

Questi tipi statici sono sufficienti per implementare ogni sistema a oggetti tipicamente dinamico che conosco.


Questo non è affatto lo stesso perché non è possibile aggiungere nuovi tipi senza rivisitare la definizione di Data.
Jed,

5
Stai mescolando concetti di tipizzazione dinamica con digitazione debole nel tuo esempio. La tipizzazione dinamica riguarda il funzionamento su tipi sconosciuti, non la definizione di un elenco di tipi consentiti e operazioni di sovraccarico tra questi.
hcalves,

2
@Jed Dopo aver implementato il modello a oggetti, i tipi fondamentali e le operazioni primitive, non sono necessarie altre basi. In questo dialetto puoi tradurre automaticamente e automaticamente i programmi nella lingua dinamica originale.
NovaDenizen,

2
@hcalves Dato che ti riferisci al sovraccarico nel mio codice Haskell, sospetto che tu non abbia la giusta idea della sua semantica. Lì ho definito un nuovo +operatore che combina due Datavalori in un altro Datavalore. Datarappresenta i valori standard nel sistema di tipi dinamici.
NovaDenizen,

1
@Jed: la maggior parte dei linguaggi dinamici ha un piccolo insieme di tipi "primitivi" e un modo induttivo per introdurre nuovi valori (strutture di dati come gli elenchi). Lo schema, ad esempio, va abbastanza lontano con poco più di atomi, coppie e vettori. Dovresti essere in grado di implementarli allo stesso modo del resto del tipo dinamico specificato.
Tikhon Jelvis,

3

Membrane :

Una membrana è un involucro attorno a un intero oggetto grafico, al contrario di un involucro per un solo oggetto. Tipicamente, il creatore di una membrana inizia a avvolgere solo un singolo oggetto in una membrana. L'idea chiave è che qualsiasi riferimento a un oggetto che attraversa la membrana è esso stesso avvolto transitivamente nella stessa membrana.

inserisci qui la descrizione dell'immagine

Ogni tipo è racchiuso da un tipo che ha la stessa interfaccia, ma che intercetta i messaggi e avvolge e scartano i valori mentre attraversano la membrana. Qual è il tipo di funzione di avvolgimento nella tua lingua preferita scritta staticamente? Forse Haskell ha un tipo per quelle funzioni, ma la maggior parte dei linguaggi tipicamente statici non lo fanno o finiscono per usare Oggetto → Oggetto, abdicando efficacemente la loro responsabilità come controlli di tipo.


4
Sì, Haskell può effettivamente farlo usando tipi esistenziali. Se disponi di una classe di tipo Foo, puoi creare un wrapper per qualsiasi tipo che istanzia tale interfaccia. class Foo a where ... data Wrapper = forall a. Foo a => Wrapper a
Jake McArthur,

@JakeMcArthur, grazie per avermi spiegato. Questa è un'altra ragione per cui mi siedo e imparo Haskell.
Mike Samuel,

2
La tua membrana è una 'interfaccia' e i tipi di oggetti sono "tipizzati esistenzialmente" - cioè, sappiamo che esistono sotto l'interfaccia, ma questo è tutto ciò che sappiamo. I tipi esistenziali per l'astrazione dei dati sono noti dagli anni '80. Un buon riferimento è cs.cmu.edu/~rwh/plbook/book.pdf capitolo 21.1
Don Stewart,

@DonStewart. Le classi proxy Java sono quindi un meccanismo di tipo esistenziale? Un posto in cui le membrane diventano difficili è nelle lingue con sistemi di tipo nominale che hanno nomi per tipi concreti visibili al di fuori della definizione di quel tipo. Ad esempio, non si può concludere Stringpoiché è un tipo concreto in Java. Smalltalk non presenta questo problema perché non tenta di digitare #doesNotUnderstand.
Mike Samuel,

1

Come qualcuno ha detto, in teoria non c'è molto che tu possa fare con la tipizzazione dinamica che non potresti fare con la tipizzazione statica se implementassi determinati meccanismi da solo. La maggior parte delle lingue fornisce meccanismi di rilassamento del tipo per supportare la flessibilità del tipo come puntatori vuoti e tipo di oggetto root o interfaccia vuota.

La domanda migliore è perché la tipizzazione dinamica sia più adatta e più appropriata in determinate situazioni e problemi.

Innanzitutto, definiamo

Entità - Avrei bisogno di una nozione generale di qualche entità nel codice. Può essere qualsiasi cosa, dal numero primitivo ai dati complessi.

Comportamento : supponiamo che la nostra entità abbia un certo stato e una serie di metodi che consentano al mondo esterno di istruire l'entità a determinate reazioni. Consente di chiamare lo stato + interfaccia di questa entità il suo comportamento. Un'entità può avere più di un comportamento combinato in un certo modo dagli strumenti forniti dal linguaggio.

Definizioni delle entità e dei loro comportamenti : ogni lingua fornisce alcuni mezzi di astrazione che ti aiutano a definire comportamenti (insieme di metodi + stato interno) di determinate entità nel programma. Puoi assegnare un nome a questi comportamenti e dire che tutte le istanze che hanno questo comportamento sono di un certo tipo .

Questo è probabilmente qualcosa che non è così sconosciuto. E come hai detto hai capito la differenza, ma comunque. Probabilmente non è una spiegazione completa e accurata, ma spero abbastanza divertente da apportare un valore :)

Digitazione statica : il comportamento di tutte le entità nel programma viene esaminato in fase di compilazione, prima che il codice venga avviato. Ciò significa che se, ad esempio, vuoi che la tua entità di tipo Persona abbia un comportamento (comportarsi come) Mago, allora dovresti definire l'entità MagicianPerson e dargli comportamenti di un mago come throwMagic (). Se nel tuo codice, dillo per errore al normale compilatore Person.throwMagic () te lo dirà"Error >>> hell, this Person has no this behavior, dunno throwing magics, no run!".

Digitazione dinamica : negli ambienti di tipizzazione dinamica i comportamenti disponibili delle entità non vengono controllati fino a quando non si tenta davvero di eseguire un'operazione con una determinata entità. L'esecuzione del codice Ruby che richiede a Person.throwMagic () non verrà catturata fino a quando il tuo codice non arriva davvero lì. Sembra frustrante, no? Ma sembra anche rivelatore. Sulla base di questa proprietà puoi fare cose interessanti. Ad esempio, supponiamo di progettare un gioco in cui tutto può trasformarsi in Mago e non sai davvero chi sarà, fino a quando non arriverai a un certo punto nel codice. E poi arriva Frog e tu diciHeyYouConcreteInstanceOfFrog.include Magice da allora in poi questa rana diventa una rana particolare che ha poteri magici. Altre rane, ancora no. Vedete, nei linguaggi di tipizzazione statici, dovreste definire questa relazione con una media standard di combinazione di comportamenti (come l'implementazione dell'interfaccia). Nel linguaggio di digitazione dinamico, puoi farlo in fase di esecuzione e a nessuno importa.

La maggior parte dei linguaggi di battitura dinamici ha meccanismi per fornire un comportamento generico che catturerà qualsiasi messaggio che viene passato alla loro interfaccia. Ad esempio Ruby method_missinge PHP __callse ricordo bene. Ciò significa che puoi fare qualsiasi tipo di cose interessanti in fase di esecuzione del programma e prendere una decisione sul tipo in base allo stato attuale del programma. Questo porta strumenti per modellare un problema che sono molto più flessibili che in, diciamo, un linguaggio di programmazione statica conservativo come Java.

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.