Qual è la differenza tra una lingua fortemente tipizzata e una lingua tipicamente statica?


Risposte:


543

Qual è la differenza tra una lingua fortemente tipizzata e una lingua tipicamente statica?

Una lingua tipizzata staticamente ha un sistema di tipi che viene verificato in fase di compilazione dall'implementazione (un compilatore o un interprete). Il controllo del tipo rifiuta alcuni programmi e i programmi che superano il controllo di solito hanno delle garanzie; ad esempio, il compilatore garantisce di non utilizzare istruzioni aritmetiche su numeri in virgola mobile.

Non esiste un vero accordo sul significato di "fortemente tipizzato", sebbene la definizione più ampiamente utilizzata nella letteratura professionale sia che in un linguaggio "fortemente tipizzato" non è possibile per il programmatore aggirare le restrizioni imposte dal sistema di tipi . Questo termine è quasi sempre usato per descrivere lingue tipicamente statiche.

Statico vs dinamico

L'opposto di un tipo statico è "un tipo dinamico", il che significa che

  1. I valori utilizzati in fase di esecuzione sono classificati in tipi.
  2. Esistono restrizioni su come utilizzare tali valori.
  3. Quando tali restrizioni vengono violate, la violazione viene segnalata come un errore di tipo (dinamico).

Ad esempio, Lua , una lingua tipizzata in modo dinamico, ha un tipo di stringa, un tipo di numero e un tipo booleano, tra gli altri. In Lua ogni valore appartiene esattamente a un tipo, ma questo non è un requisito per tutte le lingue tipizzate dinamicamente. In Lua, è consentito concatenare due stringhe, ma non è consentito concatenare una stringa e un valore booleano.

Forte contro debole

L'opposto di "fortemente tipizzato" è "tipizzato debolmente", il che significa che è possibile aggirare il sistema di tipi. C è notoriamente tipizzato debolmente perché qualsiasi tipo di puntatore è convertibile in qualsiasi altro tipo di puntatore semplicemente lanciando. Pascal doveva essere fortemente tipizzato, ma una svista nel design (record di varianti senza tag) ha introdotto una scappatoia nel sistema di tipi, quindi tecnicamente è tipizzato debolmente. Esempi di linguaggi fortemente tipizzati includono CLU, Standard ML e Haskell. ML standard ha infatti subito diverse revisioni per rimuovere le lacune nel sistema di tipi che sono state scoperte dopo che la lingua è stata ampiamente diffusa.

Cosa sta succedendo davvero qui?

Nel complesso, risulta essere poco utile parlare di "forte" e "debole". Se un sistema di tipo ha una scappatoia è meno importante del numero esatto e della natura delle scappatoie, quanto è probabile che si verifichino nella pratica e quali sono le conseguenze dello sfruttamento di una scappatoia. In pratica, è meglio evitare i termini "forte" e "debole" del tutto , perché

  • I dilettanti spesso li confondono con "statico" e "dinamico".

  • Apparentemente la "tipizzazione debole" è usata da alcune persone per parlare della prevalenza relativa o dell'assenza di conversioni implicite.

  • I professionisti non possono concordare esattamente cosa significano i termini.

  • Nel complesso, è improbabile che tu informi o illumini il tuo pubblico.

La triste verità è che quando si tratta di sistemi di tipo, "forte" e "debole" non hanno un significato tecnico universalmente concordato. Se si desidera discutere della forza relativa dei sistemi di tipo, è meglio discutere esattamente quali garanzie sono e non vengono fornite. Ad esempio, una buona domanda da porsi è questa: "è garantito che ogni valore di un dato tipo (o classe) sia stato creato chiamando uno dei costruttori di quel tipo?" In C la risposta è no. In CLU, F # e Haskell è sì. Per C ++ non ne sono sicuro, vorrei saperlo.

Al contrario, la digitazione statica significa che i programmi vengono controllati prima di essere eseguiti e che un programma potrebbe essere rifiutato prima di avviarsi. La digitazione dinamica significa che i tipi di valori vengono controllati durante l' esecuzione e un'operazione tipizzata male può causare l'interruzione del programma o la segnalazione di un errore in fase di esecuzione. Un motivo principale per la tipizzazione statica è di escludere i programmi che potrebbero avere tali "errori di tipo dinamico".

L'uno implica l'altro?

A livello pedante, no, perché la parola "forte" in realtà non significa nulla. Ma in pratica, le persone fanno quasi sempre una delle due cose:

  • Usano (erroneamente) "forte" e "debole" per indicare "statico" e "dinamico", nel qual caso (erroneamente) usano "fortemente tipizzato" e "tipicamente statico" in modo intercambiabile.

  • Usano "forte" e "debole" per confrontare le proprietà dei sistemi di tipo statico. È molto raro sentire qualcuno parlare di un sistema di tipo dinamico "forte" o "debole". Ad eccezione di FORTH, che in realtà non ha alcun tipo di sistema di tipi, non riesco a pensare a un linguaggio tipizzato in modo dinamico in cui il sistema di tipi possa essere sovvertito. Ordinati per definizione, questi controlli sono inseriti nel motore di esecuzione e ogni operazione viene verificata per ragioni di integrità prima di essere eseguita.

Ad ogni modo, se una persona chiama una lingua "fortemente tipizzata", è molto probabile che quella persona stia parlando di una lingua tipizzata staticamente.


3
@Adam: Evidentemente non abbastanza corretto da essere votato :) Poiché la risposta di Cletus contiene così tanti malintesi (anche se ne ho risolto il peggio), mi sono sentito costretto a precisare tutto con le parole di una sillaba ...
Norman Ramsey,

1
Bene, ti ho votato :) Anche la parola "compilare" non è chiara con le VM di oggi che eseguono linguaggi dinamici. Tecnicamente Java e C # sono entrambi compilati due volte (JIT) ed entrambi eseguono alcune analisi di tipo. Un linguaggio come Javascript in esecuzione in .NET vm potrebbe essere più Typesafe a causa della VM.
Adam Gent,

2
Sono così confuso ora! Ok, cari grandi gladiatori dell'arena, un'anima povera come me può seguire la seguente semplice comprensione? 1. Statico: i valori sono associati al tipo durante il tempo di compilazione e non durante il tempo di esecuzione.2.Dinamico: i valori sono associati al tipo durante il runtime, quindi il tipo di valore può cambiare durante il runtime ~ quindi è più incline al tipo di problemi relativi al casting durante il runtime. 3. Forte / debole: dimenticalo! Questi non sono termini tecnici e solo cattiva nomenclatura. Dipende dal contesto di cui si sta parlando. Posso continuare la mia vita con questa semplice comprensione? :(
Saurabh Patil,

"è garantito che ogni valore di un dato tipo (o classe) sia stato creato chiamando uno dei costruttori di quel tipo?" In C la risposta è no. Qualcuno potrebbe fornire una situazione di esempio in cui ciò si verifica in C? Suppongo che implichi il cast di puntatori a strutture?
corazza,

Digitazione forte e debole: nessuna tale classificazione.
Raúl,

248

Questo è spesso frainteso, quindi lasciatemi chiarire.

Digitazione statica / dinamica

La tipizzazione statica è dove il tipo è associato alla variabile . I tipi vengono controllati in fase di compilazione.

La tipizzazione dinamica è dove il tipo è associato al valore . I tipi vengono controllati in fase di esecuzione.

Quindi in Java per esempio:

String s = "abcd";

ssarà "per sempre" a String. Durante la sua vita può indicare diverse Strings (poiché sè un riferimento in Java). Potrebbe avere un nullvalore ma non farà mai riferimento a a Integero a List. Questa è la tipizzazione statica.

In PHP:

$s = "abcd";          // $s is a string
$s = 123;             // $s is now an integer
$s = array(1, 2, 3);  // $s is now an array
$s = new DOMDocument; // $s is an instance of the DOMDocument class

Questa è una digitazione dinamica.

Digitazione forte / debole

(Modifica avviso!)

La tipizzazione forte è una frase senza un significato ampiamente concordato. La maggior parte dei programmatori che usano questo termine per indicare qualcosa di diverso dalla tipizzazione statica lo usano per implicare che esiste una disciplina di tipo che viene applicata dal compilatore. Ad esempio, CLU ha un sistema di tipo forte che non consente al codice client di creare un valore di tipo astratto se non utilizzando i costruttori forniti dal tipo. C ha un sistema di tipi piuttosto forte, ma può essere "sovvertito" in una certa misura perché un programma può sempre trasmettere un valore di un tipo di puntatore a un valore di un altro tipo di puntatore. Quindi, ad esempio, in C puoi prendere un valore restituito malloc()e gettarlo allegramente in FILE*, e il compilatore non cercherà di fermarti, o addirittura avvertirti che stai facendo qualcosa di pericoloso.

(La risposta originale diceva qualcosa su un valore "che non cambiava il tipo in fase di esecuzione". Ho conosciuto molti progettisti di lingue e scrittori di compilatori e non ne ho conosciuto uno che parlava di valori che cambiano tipo in fase di esecuzione, tranne forse qualche ricerca molto avanzata nel tipo sistemi, in cui questo è noto come "forte problema di aggiornamento".)

La digitazione debole implica che il compilatore non impone una discline di battitura o che l'applicazione può essere facilmente sovvertita.

L'originale di questa risposta combinava la digitazione debole con la conversione implicita (talvolta chiamata anche "promozione implicita"). Ad esempio, in Java:

String s = "abc" + 123; // "abc123";

Questo codice è un esempio di promozione implicita: 123 viene convertito implicitamente in una stringa prima di essere concatenato "abc". Si può sostenere che il compilatore Java riscriva quel codice come:

String s = "abc" + new Integer(123).toString();

Considera un classico problema "inizia con" di PHP:

if (strpos('abcdef', 'abc') == false) {
  // not found
}

L'errore qui è che strpos()restituisce l'indice della corrispondenza, essendo 0. 0 viene forzato in booleano falsee quindi la condizione è effettivamente vera. La soluzione è utilizzare ===invece di ==evitare la conversione implicita.

Questo esempio mostra come una combinazione di conversione implicita e tipizzazione dinamica può portare fuori strada i programmatori.

Confronta quello con Ruby:

val = "abc" + 123

che è un errore di runtime perché in Ruby l' oggetto 123 non viene convertito implicitamente solo perché sembra essere passato a un +metodo. In Ruby il programmatore deve rendere esplicita la conversione:

val = "abc" + 123.to_s

Il confronto tra PHP e Ruby è una buona illustrazione qui. Entrambi sono linguaggi tipizzati dinamicamente, ma PHP ha molte conversioni implicite e Ruby (forse sorprendentemente se non si ha familiarità con esso) no.

Statico / dinamico vs forte / debole

Il punto qui è che l'asse statico / dinamico è indipendente dall'asse forte / debole. Le persone li confondono probabilmente in parte perché la tipizzazione forte contro debole non è solo meno chiaramente definita, non esiste un vero consenso su cosa si intenda per forte e debole. Per questo motivo la tipizzazione forte / debole è molto più di una sfumatura di grigio piuttosto che nera o bianca.

Quindi, per rispondere alla tua domanda: un altro modo di vedere ciò che è per lo più corretto è quello di dire che la tipizzazione statica è la sicurezza del tipo in fase di compilazione e la tipizzazione forte è la sicurezza del tipo di runtime.

La ragione di ciò è che le variabili in una lingua tipizzata staticamente hanno un tipo che deve essere dichiarato e che può essere verificato in fase di compilazione. Un linguaggio fortemente tipizzato ha valori che hanno un tipo in fase di esecuzione ed è difficile per il programmatore sovvertire il sistema di tipi senza un controllo dinamico.

Ma è importante capire che un linguaggio può essere statico / forte, statico / debole, dinamico / forte o dinamico / debole.


Invece di dire $ s è un numero intero o una stringa, sarebbe meglio se dici che il tipo è associato con "abcd" o 1234 non con la variabile $ s.
Srinivas Reddy Thatiparthy,

Ottima risposta con esempi chiari. Tuttavia, penso che non affronti completamente la confusione su PERCHÉ le persone chiedono di strong / static come una coppia gemella di concetti. Ad esempio, la formulazione del PO di "la tipizzazione statica IMPLY digita forte?" La tua risposta sottolinea la loro indipendenza. Per continuare il chiarimento del perché il forte è spesso associato con statico, risposta precedente di Norman Ramsey è molto buono: stackoverflow.com/questions/376611/...
JasDev

1
"abc" + 123è un errore di runtime , non un errore di compilazione in ruby. Se si trattasse di un errore di compilazione, il rubino verrebbe digitato staticamente.
sepp2k,

Gli esempi di digitazione deboli devono essere migliorati (vedi la mia risposta) ma per il resto bella formulazione.
Adam Gent,

Nel mio opion, il carattere forte vs debole è questo: Forte: "c" + Vero = errore di runtime o errore di tempo di compilazione. Debole: "c" + True = "b" o "d" perché tutto viene trattato come byte non elaborati. Strong: C #, Ruby, C ++ Debole: Assembly, C (a causa di impliciti vuoti puntatori)
Jonathan Allen

17

Entrambi sono poli su due assi diversi:

  • fortemente tipizzato vs. debolmente tipizzato
  • tipizzato staticamente vs. digitato dinamicamente

Significa fortemente tipizzato , a non verrà convertito automaticamente da un tipo a un altro. Digitato debolmente è l'opposto: Perl può usare una stringa come "123"in un contesto numerico, convertendolo automaticamente in int 123. Un linguaggio fortemente tipizzato come Python non lo farà.

Significato tipicamente significa, il compilatore capisce il tipo di ogni variabile al momento della compilazione. I linguaggi tipizzati dinamicamente determinano solo i tipi di variabili in fase di esecuzione.


6
Non sono d'accordo. Un linguaggio fortemente tipizzato è uno che sa quali sono i tipi in fase di esecuzione. Un linguaggio debolmente tipizzato è un linguaggio a cui non piace Assembly. Il tuo esempio è su un terzo asse, "conversioni implicite vs esplicite".
Jonathan Allen,

1
In realtà normale, sono d'accordo con Jonathan, ma non è necessario che i tipi disponibili in fase di esecuzione siano fortemente tipizzati se si esegue un'analisi statica completa e non si consente il casting. (vedi la mia risposta modificata).
Adam Gent,

1
Python è un esempio di un linguaggio tipizzato in modo dinamico e fortemente tipizzato
MaRoBet,

13

Caratterizzato in modo forte significa che ci sono restrizioni tra le conversioni tra tipi. Digitato staticamente significa che i tipi non sono dinamici: non è possibile modificare il tipo di una variabile dopo che è stata creata.


Per dimostrarlo: in un linguaggio fortemente tipizzato, non è possibile confrontare "5" == 5 e renderlo vero: le stringhe non sono numeri interi. Se la mia memoria serve, i più moderni linguaggi di scripting sono fortemente tipizzati in modo dinamico. Tcl / Tk, tuttavia, è tipizzato debolmente - Tutto può essere trattato come una stringa.
Tavolini Bobby,

Bobby, in una lingua debolmente tipizzata "5" == 5 viene letto come 0x35 == 0x05. O in altre parole, tutto viene trattato come byte non elaborati.
Jonathan Allen,

Non sono d'accordo con entrambi. Prendi Lua; puoi confrontare "5" == 5 e restituirà false, tuttavia è possibile effettuare una conversione rapida andando "5" + 0.
RCIX

12

Coercizione dei dati non significa necessariamente tipicamente debolmente perché a volte il suo zucchero sintattico:

L'esempio sopra di Java viene debolmente digitato a causa di

String s = "abc" + 123;

Non è un esempio debolmente tipizzato perché sta davvero facendo:

String s = "abc" + new Integer(123).toString()

Anche la coercizione dei dati non viene tipizzata debolmente se si sta costruendo un nuovo oggetto. Java è un pessimo esempio di digitazione debole (e qualsiasi linguaggio che abbia una buona riflessione probabilmente non verrà digitato debolmente). Perché il runtime della lingua sa sempre qual è il tipo (l'eccezione potrebbe essere i tipi nativi).

Questo è diverso da C. C è uno dei migliori esempi di caratteri deboli. Il runtime non ha idea se 4 byte sono un numero intero, uno struct, un puntatore o un 4 caratteri.

Il runtime del linguaggio definisce davvero se è tipicamente debolmente scritto altrimenti è davvero solo un'opinione.

EDIT: dopo ulteriori considerazioni questo non è necessariamente vero in quanto il runtime non deve avere tutti i tipi reificati nel sistema di runtime per essere un sistema fortemente tipizzato. Haskell e ML hanno un'analisi statica così completa che possono potenzialmente ottenere informazioni sul tipo di ommit dal runtime.


B è probabilmente un esempio migliore, anche se un po 'meno noto.
Tom Hawtin - tackline il

Anche Javascript è un tipo piuttosto debole ma perché ci sono così pochi tipi e perché non puoi davvero costruirne di nuovi.
Adam Gent,

10

La risposta è già stata data sopra. Cercando di distinguere tra concetto forte vs settimana e concetto statico vs dinamico.

Che cosa è fortemente tipizzato VS tipicamente debole?

Caratterizzato fortemente: non verrà convertito automaticamente da un tipo a un altro

In Go o Python come i linguaggi fortemente tipizzati "2" + 8 genererà un errore di tipo, perché non consentono la "coercizione di tipo".

Digitato debolmente (liberamente): verrà automaticamente convertito in un tipo in un altro: linguaggi debolmente digitati come JavaScript o Perl non genereranno un errore e in questo caso JavaScript genererà '28' e perl risulterà 10.

Esempio Perl:

my $a = "2" + 8;
print $a,"\n";

Salvalo su main.pl ed esegui perl main.ple otterrai l'output 10.

Che cos'è il tipo statico VS dinamico?

Nella programmazione, il programmatore definisce la tipizzazione statica e la digitazione dinamica rispetto al punto in cui vengono controllati i tipi di variabili. Le lingue tipizzate statiche sono quelle in cui viene eseguita la verifica del tipo in fase di compilazione, mentre le lingue tipizzate dinamiche sono quelle in cui viene eseguita la verifica del tipo in fase di esecuzione.

  • Statico: tipi controllati prima del runtime
  • Dinamica: tipi controllati al volo, durante l'esecuzione

Cosa significa questo?

In Vai controlla digitato prima del runtime (controllo statico). Ciò significa che non solo traduce e verifica il codice che sta eseguendo, ma eseguirà la scansione di tutto il codice e verrebbe generato un errore di tipo prima ancora che il codice venga eseguito. Per esempio,

package main

import "fmt"

func foo(a int) {
    if (a > 0) {
        fmt.Println("I am feeling lucky (maybe).")
    } else {
        fmt.Println("2" + 8)
    }
}

func main() {
    foo(2)
}

Salvare questo file in main.go ed eseguirlo, verrà visualizzato un messaggio di compilazione non riuscita per questo.

go run main.go
# command-line-arguments
./main.go:9:25: cannot convert "2" (type untyped string) to type int
./main.go:9:25: invalid operation: "2" + 8 (mismatched types string and int)

Ma questo caso non è valido per Python. Ad esempio, il seguente blocco di codice verrà eseguito per la prima chiamata foo (2) e non riuscirà per la seconda chiamata foo (0). È perché Python è digitato in modo dinamico, traduce e verifica solo il codice su cui è in esecuzione. Il blocco else non viene mai eseguito per foo (2), quindi "2" + 8 non viene mai nemmeno guardato e per foo (0) call tenterà di eseguire quel blocco e fallirà.

def foo(a):
    if a > 0:
        print 'I am feeling lucky.'
    else:
        print "2" + 8
foo(2)
foo(0)

Vedrai il seguente output

python main.py
I am feeling lucky.
Traceback (most recent call last):
  File "pyth.py", line 7, in <module>
    foo(0)
  File "pyth.py", line 5, in foo
    print "2" + 8
TypeError: cannot concatenate 'str' and 'int' objects

8

Uno non implica l'altro. Per una lingua da digitare staticamente significa che i tipi di tutte le variabili sono conosciuti o dedotti al momento della compilazione.

Un linguaggio fortemente tipizzato non ti consente di utilizzare un tipo come un altro. C è una lingua tipicamente debolmente ed è un buon esempio di ciò che le lingue fortemente tipizzate non consentono. In C puoi passare un elemento di dati del tipo sbagliato e non ti lamenterà. In lingue fortemente tipizzate non puoi.


7

La tipizzazione forte significa probabilmente che le variabili hanno un tipo ben definito e che esistono regole rigide sulla combinazione di variabili di tipi diversi nelle espressioni. Ad esempio, se A è un numero intero e B è un float, la regola rigida su A + B potrebbe essere che A viene trasmesso a un float e il risultato restituito come float. Se A è un numero intero e B è una stringa, la regola rigida potrebbe essere che A + B non è valido.

La tipizzazione statica probabilmente significa che i tipi sono assegnati al momento della compilazione (o il suo equivalente per i linguaggi non compilati) e non possono cambiare durante l'esecuzione del programma.

Nota che queste classificazioni non si escludono a vicenda, anzi mi aspetto che si verifichino frequentemente insieme. Molte lingue fortemente tipizzate sono anche tipizzate staticamente.

E nota che quando uso la parola "probabilmente" è perché non ci sono definizioni universalmente accettate di questi termini. Come avrai già visto dalle risposte finora.

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.