Perché le lingue digitate dinamicamente non consentono allo sviluppatore di specificare il tipo?

14

Le lingue digitate dinamicamente che conosco non consentono mai agli sviluppatori di specificare i tipi di variabili, o almeno di avere un supporto molto limitato.

JavaScript, per esempio, non fornisce alcun meccanismo per applicare tipi di variabili quando è conveniente farlo. PHP ti permette di specificare alcuni tipi di argomenti del metodo, ma non c'è modo di usare i tipi nativi ( int , string , ecc.) Per gli argomenti, e non c'è modo di imporre i tipi per qualcosa di diverso dagli argomenti.

Allo stesso tempo, sarebbe opportuno avere una scelta per specificare in alcuni casi il tipo di una variabile in una lingua digitata dinamicamente, invece di eseguire manualmente la verifica del tipo.

Perché esiste una tale limitazione? È per ragioni tecniche / prestazionali (suppongo sia nel caso di JavaScript), o solo per ragioni politiche (che è, credo, il caso di PHP)? Questo è un caso per altre lingue digitate dinamicamente che non mi sono familiari?

Modifica: in seguito alle risposte e ai commenti, ecco un esempio di chiarimento: diciamo che abbiamo il seguente metodo in formato PHP:

public function CreateProduct($name, $description, $price, $quantity)
{
    // Check the arguments.
    if (!is_string($name)) throw new Exception('The name argument is expected to be a string.');
    if (!is_string($description)) throw new Exception('The description argument is expected to be a string.');
    if (!is_float($price) || is_double($price)) throw new Exception('The price argument is expected to be a float or a double.');
    if (!is_int($quantity)) throw new Exception('The quantity argument is expected to be an integer.');

    if (!$name) throw new Exception('The name argument cannot be an empty string.');
    if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
    if ($price < 0) throw new Exception('The price argument cannot be less than zero.');

    // We can finally begin to write the actual code.
    // TODO: Implement the method here.
}

Con alcuni sforzi, questo può essere riscritto come (vedi anche Programmazione per contratto in PHP ):

public function CreateProduct($name, $description, $price, $quantity)
{
    Component::CheckArguments(__FILE__, __LINE__, array(
        'name' => array('value' => $name, 'type' => VTYPE_STRING),
        'description' => array('value' => $description, 'type' => VTYPE_STRING),
        'price' => array('value' => $price, 'type' => VTYPE_FLOAT_OR_DOUBLE),
        'quantity' => array('value' => $quantity, 'type' => VTYPE_INT)
    ));

    if (!$name) throw new Exception('The name argument cannot be an empty string.');
    if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
    if ($price < 0) throw new Exception('The price argument cannot be less than zero.');

    // We can finally begin to write the actual code.
    // TODO: Implement the method here.
}

Ma lo stesso metodo sarebbe scritto come segue se PHP accettasse facoltativamente i tipi nativi per gli argomenti:

public function CreateProduct(string $name, string $description, double $price, int $quantity)
{
    // Check the arguments.
    if (!$name) throw new Exception('The name argument cannot be an empty string.');
    if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
    if ($price < 0) throw new Exception('The price argument cannot be less than zero.');

    // We can finally begin to write the actual code.
    // TODO: Implement the method here.
}

Quale è più breve da scrivere? Quale è più facile da leggere?

    
posta Arseni Mourzenko 09.05.2011 - 12:54
fonte

10 risposte

17

Il punto di avere la tipizzazione statica è la capacità di dimostrare staticamente che il tuo programma è corretto per quanto riguarda i tipi (nota: non completamente corretto in tutti i sensi). Se si dispone di un sistema di tipo statico in tutto, è possibile rilevare gli errori di tipo la maggior parte del tempo.

Se si dispone solo di informazioni di tipo parziale, è possibile controllare solo i frammenti di un grafico di chiamata in cui le informazioni sul tipo sembrano essere complete. Ma hai speso tempo e sforzi per specificare le informazioni sul tipo per le parti incomplete, dove non può aiutarti ma potrebbe dare un falso senso di sicurezza.

Per esprimere le informazioni sul tipo, è necessaria una parte del linguaggio che non può essere eccessivamente semplice. Presto scoprirai che informazioni come int non sono sufficienti; vorrai qualcosa come List<Pair<Int, String>> , quindi tipi parametrici, ecc. Può essere abbastanza confuso anche nel caso piuttosto semplice di Java.

Quindi, dovrai gestire queste informazioni durante la fase di esecuzione e della fase di traduzione, perché è sciocco controllare solo gli errori statici; l'utente si aspetta che i vincoli di tipo siano sempre validi se specificato. Le lingue dinamiche non sono troppo veloci come sono e tali controlli rallentano ulteriormente le prestazioni. Un linguaggio statico può impiegare seri tipi di controllo dello sforzo perché lo fa solo una volta; un linguaggio dinamico non può.

Ora immagina di aggiungere e mantenere tutto questo solo in modo che le persone a volte facoltativamente abbiano usato queste funzionalità, rilevando solo una piccola parte degli errori di tipo. Non penso che ne valga la pena.

Il vero punto dei linguaggi dinamici è di avere un framework molto piccolo e molto malleabile, all'interno del quale puoi facilmente fare cose che sono molto più coinvolte quando eseguite in un linguaggio statico: varie forme di patch-scimmia che sono usate per metaprogrammazione , derisione e test, sostituzione dinamica del codice, ecc. Smalltalk e Lisp, entrambi molto dinamici, lo hanno portato a un livello così estremo da spedire le immagini dell'ambiente invece di costruire dalla fonte. Ma quando vuoi assicurarti che determinati percorsi dati siano sicuri per il tipo, aggiungi asserzioni e scrivi più test unitari.

    
risposta data 09.05.2011 - 14:27
fonte
8

Nella maggior parte dei linguaggi dinamici, puoi almeno provare dinamicamente il tipo di un oggetto o valore.

E ci sono infernali di tipo statico, controllori e / o esecutori per alcune lingue dinamiche: ad es.

E Perl 6 supporterà un opzionale digita sistema con digitazione statica.

Ma immagino che la linea di fondo sia che molte persone usano linguaggi dinamici perché sono digitati dinamicamente, e per loro la digitazione statica facoltativa è molto "ho hum". E molte altre persone li usano perché sono "facili da usare per i non programmatori", in gran parte come conseguenza della digitazione dinamica della natura tollerante. Per loro, la digitazione opzionale è qualcosa che non capiranno o che non saranno disturbati da usare.

Se fossi cinico, potresti dire che la digitazione statica opzionale offre il peggiore dei due mondi. Per uno zealot di tipo statico, non impedisce errori di tipo dinamico tutti . Per una ventola di tipo dinamico, è ancora una giacca dritta ... anche se le cinghie non sono ben strette.

    
risposta data 09.05.2011 - 13:04
fonte
2

Javascript prevedeva di includere alcuni tipi di digitazione statica facoltativa e sembra che molti linguaggi dinamici maturi si stiano dirigendo in quel modo -

Il motivo è che quando si esegue il primo codice, si desidera essere digitato in modo rapido e dinamico. Una volta che il codice è solido, funzionante e ha molti usi (r) s, si desidera bloccare il progetto per ridurre gli errori. (questo è vantaggioso sia per gli utenti che per gli sviluppatori, in quanto il primo otterrà il controllo degli errori sulle loro chiamate e quest'ultimo non interromperà le cose casualmente.

Per me ha un senso, dal momento che di solito trovo troppo controllo dei caratteri all'inizio di un progetto, troppo poco alla fine della sua vita, indipendentemente dalla lingua che uso;).

    
risposta data 09.05.2011 - 13:56
fonte
2

Gli oggetti Python do hanno un tipo.

Specifica il tipo quando crei l'oggetto.

At the same time, it would be convenient to have a choice to specify in some cases the type of a variable in a dynamically typed language, instead of doing the type check manually.

In realtà, un controllo manuale del tipo in Python è quasi sempre una perdita di tempo e codice.

È semplicemente una cattiva pratica scrivere codice di controllo del tipo in Python.

Se un tipo inappropriato è stato utilizzato da un sociopatico malevolo, i metodi ordinari di Python genereranno un'eccezione normale quando il tipo non è appropriato.

Non scrivi codice, il tuo programma fallisce ancora con un TypeError .

Ci sono casi molto rari in cui è necessario determinare il tipo in fase di esecuzione.

Why there is such limitation?

Poiché non si tratta di una "limitazione", la domanda non è una vera domanda.

    
risposta data 09.05.2011 - 21:04
fonte
2

Il più delle volte, non è necessario, almeno non al livello di dettaglio che stai suggerendo. In PHP, gli operatori che usi rendono perfettamente chiaro cosa ti aspetti che gli argomenti siano; è un po 'un controllo del design, anche se PHP interpreterà i tuoi valori se possibile, anche quando passi una matrice a un'operazione che si aspetta una stringa, e poiché il cast non è sempre significativo, a volte ottieni risultati strani ( e questo è esattamente dove i controlli di tipo sono utili). Oltre a questo, non importa se aggiungi interi 1 e 5 o stringhe "1" e "5" - il semplice fatto che stai utilizzando i segnali operatore + a PHP che vuoi trattare gli argomenti come numeri e PHP obbedirà. Una situazione interessante è quando ricevi i risultati delle query da MySQL: molti valori numerici vengono semplicemente restituiti come stringhe, ma non ti accorgerai dato che PHP li lancia per te ogni volta che li tratti come numeri.

Python è un po 'più severo riguardo ai suoi tipi, ma a differenza di PHP, Python ha avuto eccezioni fin dall'inizio e lo usa coerentemente. Il paradigma "più facile chiedere perdono che permesso" suggerisce di eseguire l'operazione senza il controllo del tipo e di fare affidamento su un'eccezione quando i tipi non hanno senso. L'unico lato negativo di ciò a cui riesco a pensare è che a volte, scoprirai che da qualche parte un tipo non corrisponde a quello che ti aspetti che sia, ma trovare il motivo può essere noioso.

E c'è un'altra ragione da considerare: i linguaggi dinamici non hanno una fase di compilazione. Anche se si dispone di vincoli di tipo, possono essere attivati solo in fase di esecuzione, semplicemente perché non c'è tempo di compilazione . Se i tuoi controlli portano comunque ad errori di runtime, è molto più semplice modellarli di conseguenza: come controlli espliciti (come is_XXX() in PHP o typeof in javascript), o lanciando eccezioni (come fa Python). Funzionalmente, si ha lo stesso effetto (un errore viene segnalato in fase di esecuzione quando un controllo di tipo fallisce), ma si integra meglio con il resto della semantica del linguaggio. Semplicemente non ha senso trattare errori di tipo fondamentalmente diversi da altri errori di runtime in un linguaggio dinamico.

    
risposta data 04.08.2011 - 21:53
fonte
0

Potresti essere interessato a Haskell - il suo tipo di sistema deduce i tipi dal codice, e puoi anche specificare i tipi.

    
risposta data 09.05.2011 - 15:43
fonte
0

Come hanno alluso alle altre risposte, ci sono due approcci alla digitazione quando si implementa un linguaggio di programmazione.

  1. Chiedi al programmatore di dirti quali sono le variabili e le funzioni utilizzate per i tipi. Idealmente, si verifica anche che le specifiche del tipo siano accurate. Quindi, poiché sai che tipo di cosa sarà in ogni luogo, puoi scrivere un codice che presuppone che la cosa appropriata sia lì e utilizza qualsiasi struttura di dati che usi per implementare quel tipo direttamente.
  2. Collegare un indicatore di tipo ai valori che verranno archiviati nelle variabili e passati e restituiti dalle funzioni. Ciò significa che il programmatore non dovrà specificare alcun tipo per variabili o funzioni, poiché i tipi effettivamente appartengono agli oggetti a cui si riferiscono le variabili e le funzioni.

Entrambi gli approcci sono validi e il loro utilizzo dipende in parte da considerazioni tecniche come le prestazioni e in parte da motivi politici come il mercato di riferimento per la lingua.

    
risposta data 09.05.2011 - 22:19
fonte
0

Innanzitutto i linguaggi dinamici sono stati creati principalmente per la facilità d'uso. Come hai già detto, è molto buono prendere automaticamente la conversione del tipo e fornirci meno costi generali. Ma allo stesso tempo manca di problemi di prestazioni.

Puoi restare fedele alle lingue dinamiche, nel caso in cui non ti preoccupi delle prestazioni. Supponiamo ad esempio che JavaScript funzioni più lentamente quando è necessario eseguire molte conversioni di tipi nel tuo programma, ma aiuta a ridurre il numero di righe nel tuo codice.

E per essere citato, ci sono altri linguaggi dinamici che consentono al programmatore di specificare il tipo. Ad esempio Groovy è uno dei famosi linguaggi dinamici che girano su JVM. Ed è stato molto famoso anche negli ultimi giorni. Si noti che le prestazioni di Groovy sono uguali a quelle di Java.

Spero che ti aiuti.

    
risposta data 10.05.2011 - 05:29
fonte
-1

Semplicemente non ha senso farlo.

Perché?

Perché il sistema di tipi di DTL è esattamente tale che i tipi non possono essere determinati in fase di compilazione. Pertanto, il compilatore non ha potuto nemmeno controllare che il tipo specificato avrebbe senso.

    
risposta data 09.05.2011 - 13:47
fonte
-1

Dai un'occhiata a Go, in superficie è tipizzato staticamente, ma quei tipi possono essere interfacce che sono essenzialmente dinamiche.

    
risposta data 05.08.2011 - 10:34
fonte