Perché le variabili hanno bisogno di un tipo?


10

Quindi scriviamo:

Customer c = new Customer();

Perché il design non è tale che scriviamo:

c = new Customer();
c.CreditLimit = 1000;

Il compilatore può elaborare c punti per un cliente e consentire ai membri del cliente di essere invocati in c?

So che potremmo voler scrivere:

IPerson c = new Customer();
IPerson e = new Employee();

per poter scrivere:

public string GetName(IPerson object)
{
    return object.Name
}

string name = GetName(c); // or GetName(e);

Ma se scrivessimo:

c = new Customer();
e = new Employee();

potremmo ancora scrivere:

public string GetName(object)
{
    return object.Name
}    

string name = GetName(c); // or GetName(e);

Il compilatore potrebbe lamentarsi del codice immediatamente sopra se il tipo di riferimenti all'oggetto c non supporta una proprietà Name (in quanto può verificare quali membri vengono utilizzati sull'argomento / parametro all'interno del metodo) o il runtime potrebbe lamentarsi.

Anche con la parola chiave dinamica di C #, stiamo ancora usando una variabile 'tipo' (determinata in fase di esecuzione). Ma perché una variabile ha bisogno di un tipo? Sono sicuro che ci deve essere una buona ragione, ma non ci posso pensare!


12
Ecco perché ci sono linguaggi dinamici come Python e Ruby (e altri). Non c'è risposta a questa domanda. È un dato di fatto che alcune lingue usano dichiarazioni di tipo e altre no.
S. Lott,

2
"le variabili in quelle lingue non hanno affatto un tipo?" Corretta. le variabili non hanno un tipo in Python. Gli oggetti hanno un tipo e le variabili sono semplicemente riferimenti ad oggetti. La tua domanda è davvero solo un'osservazione. In particolare "non tutte le lingue richiedono dichiarazioni variabili". Non c'è risposta Quindi è probabile che si chiuderà come non costruttivo.
S. Lott,

1
Potresti dare un'occhiata a Boo , che ti consente di dichiarare variabili senza dichiarazioni di tipo, ma usa l' inferenza di tipo per capire i tipi in modo da non sacrificare la correttezza e i vantaggi in termini di prestazioni della tipizzazione forte.
Mason Wheeler,

2
var x = 1; - intendevi numero a 32 bit, 64 bit, 16 bit? byte? galleggiante? Doppio? decimale? Si tratta solo di primitivi.
Lavoro

4
Puoi usare varin C # ed essere esplicito su dove vuoi dichiarare che una variabile è sempre buona.
Daniel Little,

Risposte:


22

Ma perché una variabile ha bisogno di un tipo?

  1. Ciò può rilevare bug in cui un'espressione non valida, erroneamente digitata, è assegnata a una variabile. Alcune lingue hanno una tipizzazione dinamica , che sacrifica le garanzie di correttezza di un tipo per variabile per il tipo di flessibilità che sembra desiderare.
  2. I tipi possono consentire al compilatore di generare codice più efficiente. La digitazione dinamica significa che i controlli del tipo devono essere eseguiti in fase di esecuzione.

1
Per favore, spiega il downvote.
Fred Foo,

4
Inoltre, la tipizzazione dinamica ha un costo in termini di prestazioni, poiché le informazioni sul tipo devono essere verificate durante il runtime.
Charles Salvia,

@CharlesSalvia: buon punto, aggiunto questo alla risposta.
Fred Foo,

2
@sturdytree: per quanto riguarda "se non ha un tipo, non può essere erroneamente digitato" - per quanto riguarda le regole del linguaggio, è vero. Ma alla variabile può ancora essere assegnato il tipo sbagliato da un punto di vista semantico , ad esempio hai sbagliato a digitare il nome di un costruttore e il programma è ancora in esecuzione, ma non fa quello che vuoi.
Fred Foo,

5
@sturdytree Mentre è vero che non ci sono lingue che hanno variabili veramente senza tipo con il controllo del tipo, ci sono lingue che hanno l' inferenza del tipo . Vale a dire, la lingua esamina l'utilizzo della variabile e ne deduce il tipo dall'uso. Se si verifica un conflitto (ad es. Si esegue a = new Bar()e successivamente si chiama un metodo dalla classe Baz), il compilatore genera un errore. Lingue come Haskell e OCaml hanno aperto la strada all'inferenza dei tipi, ma è presente in C #, con la varparola chiave.
quantico

9

Hai un punto perfettamente valido, esistono lingue che non tengono traccia del tipo di una variabile e sono chiamate "tipizzate dinamicamente". La categoria include lingue come JavaScript, Perl, Lisp e Python.

Il vantaggio che otteniamo da una lingua tipizzata staticamente è un ulteriore controllo degli errori in fase di compilazione.

Supponiamo, ad esempio, di avere il seguente metodo:

public addCustomerContact(Customer client, Employee contact) {
   ...
} 

Sarebbe possibile, se hai un cliente bobe un dipendente jamesnel tuo codice, chiamare erroneamente addCustomerContact(james, bob), che non è valido. Ma se il compilatore non conosce i tipi di variabili, non può avvisarti che hai effettuato una chiamata non valida, invece, si verifica un errore in fase di esecuzione ... e poiché i linguaggi di tipo dinamico non controllano il tipo di parametri passati ai metodi, tale problema si verifica ogni volta che il codice tenta di utilizzare le proprietà solo cliente jamesdell'oggetto o le proprietà solo dipendente bobdell'oggetto. Potrebbe passare molto tempo dopo che la coppia (james, bob) è stata aggiunta all'elenco dei contatti dei clienti.

Ora, potresti chiederti, perché il compilatore non può ancora dedurre il tipo di jamese bob, e ancora avvisarci? Questo a volte può essere possibile, ma se le variabili non hanno davvero alcun tipo, allora potremmo fare quanto segue:

var james;
var bob;
if (getRandomNumber() > 0.5) {
   james = new Customer();
   bob = new Employee();
} else {
   james = new Employee();
   bob = new Customer();
}

È perfettamente legale assegnare qualsiasi valore a qualsiasi variabile, poiché abbiamo detto che le variabili non hanno alcun tipo. Ciò significa anche che non possiamo sempre conoscere il tipo di una variabile, perché potrebbe essere di diversi tipi in base a percorsi di esecuzione diversi.

In generale, i linguaggi tipizzati dinamicamente vengono utilizzati per i linguaggi di scripting, in cui non esiste una fase di compilazione e quindi non esistono errori di compilazione, il che significa che i tasti aggiuntivi necessari per fornire il tipo di variabili non sarebbero molto utili.

Ci sono alcuni vantaggi distinti anche nei linguaggi tipizzati dinamicamente, principalmente in termini di meno codice necessario per implementare lo stesso design: le interfacce non devono essere scritte, perché tutto è "tipizzato" (ci interessa solo quali metodi / proprietà ha un oggetto , non a quale classe appartiene l'oggetto), non è necessario assegnare un tipo esplicito alle variabili ... con il compromesso che scopriamo un po 'meno bug prima di iniziare a eseguire il nostro codice.


Grazie Teodoro. "Ma se il compilatore non conosce i tipi di variabili, non può avvisarti che hai effettuato una chiamata non valida" Come accennato, il compilatore può conoscere i tipi di oggetti a cui puntano le variabili.
sturdytree,

Teodoro: Nel tuo esempio james / bob, come programmatori dovremmo sapere come abbiamo usato le nostre variabili (e il buon nome aiuta) e quindi non vedo alcun problema. Quando dici "non possiamo sempre conoscere il tipo di una variabile" Presumo che intendi che non possiamo sempre conoscere il tipo di oggetto a cui punta la variabile, ma il compilatore può risolverlo e quindi avvisare che i membri errati sono applicato (cioè possiamo avere un controllo statico).
sturdytree,

2
Ho dato un esempio sopra in cui non è possibile conoscere staticamente i tipi di oggetti ... a seconda del percorso di esecuzione, il tipo di oggetto memorizzato in una variabile senza informazioni sui tipi può essere diverso. Puoi avere un linguaggio come C # in cui è possibile dedurre le informazioni sul tipo di tempo di compilazione, ma, per quanto ne so, non esiste un linguaggio con il controllo statico del tipo e variabili davvero non tipabili, è probabile anche la complessità computazionale dell'analisi statica grande.
Theodore Murdock,

Theodore, grazie, hai capito bene che quello di cui sto parlando è un linguaggio con controllo statico del tipo (basato sul tipo di oggetto) e variabili senza tipo. Triste nel sentire che non ce ne sono - mi viene detto che Python ha variabili senza tipo, ma sembra che non abbia un controllo statico del tipo.
sturdytree,

1
-1; la tipizzazione forte / debole è ortogonale alla tipizzazione statica / dinamica. C è staticamente tipizzato debolmente; Lisp e Python sono entrambi fortemente dinamicamente tipizzati.
Fred Foo,

5

Quindi i programmatori professionisti non devono capire se

10 + "10"

is "1010" or 20....

Che cos'è un errore, al momento della compilazione con una lingua tipicamente statica o runtime con una lingua tipizzata in modo dinamico. Beh, quelli sani di mente comunque.


2
Cioè, il Perl non è una lingua sana? :)
Fred Foo,

5
@larsmans: in realtà no, non lo è. ma questa è puramente opinione.
NotMe,

2
@ChrisLively: sono contento che sia un dato di fatto ora. Per favore, vieni dal mio posto di lavoro in qualsiasi momento per convincere i miei colleghi amanti del Perl;)
Fred Foo,

2
10 + "10" sta utilizzando un operatore '+' sull'oggetto di tipo intero e sull'oggetto di tipo stringa. Il compilatore genererebbe un errore. La mia domanda riguarda il tipo di variabile, non l'oggetto.
robusto

2
Si è valida C: E 'l'aritmetica dei puntatori.
dan04,

4

Supponendo di avere una variabile one(impostata su 1) e di aver tentato di valutare one + one. Se non hai idea del tipo, allora 1 + 1 sarà ambiguo. Puoi sostenere che 2 o 11 potrebbero essere risposte corrette. Diventa ambiguo se non viene dato il contesto.

Ho visto che ciò accadeva in SQLite, dove i tipi di database erano inavvertitamente impostati VARCHARinvece di INTe quando le operazioni venivano eseguite le persone stavano ottenendo risultati inaspettati.

In c # se il contesto fornisce un tipo, puoi usare la varparola chiave.

var c = new Customer();
var e = new Employer();

Compilerà c ed e con i tipi inferiti al momento della compilazione.


1
In Python 1 + 1ha sempre il tipo int, ma non è necessario dichiararlo. La domanda è perché le variabili hanno un tipo, non valori .
Fred Foo,

Mi dispiace che variablesnon valuesdovessi vedere quando ho usato il 1 + 1mio esempio. Immagino non fosse chiaro.
Stephen Quan,

Tuttavia, le lingue tipizzate dinamicamente possono far fronte a questo. In Python, one=1; print(one+one)stampe 2. one="1"; print(one+one)stampe 11. L'esempio di SQLite è più convincente, ma il problema è quello della digitazione debole, quindi non è rilevante per C #.
Fred Foo,

Nel mio schema suggerito, uno = 1 indica una variabile che punta a un tipo intero (non sto suggerendo alcun tipo - gli oggetti avrebbero un tipo). uno + uno non sarebbe quindi ambiguo (stiamo aggiungendo due oggetti / valori interi)
sturdytree

1
Ciao @ dan04, ho visto con i ORDER BYinavvertitamente fatto su un VARCHARcampo. Vedi stackoverflow.com/questions/9103313/… .
Stephen Quan,

4

Non è necessario che una variabile abbia un tipo associato. Le lingue in cui questo è vero includono Lisp, Scheme, Erlang, Prolog, Smalltalk, Perl, Python, Ruby e altri.

È anche possibile che una variabile abbia un tipo, ma potresti non dover scrivere il tipo nel programma. Questo di solito si chiama inferenza di tipo. ML, Haskell e i loro discendenti hanno una potente inferenza di tipo; alcune altre lingue lo hanno in forme minori, come le autodichiarazioni del C ++ .

L'argomento principale contro l'inferenza di tipo è che danneggia la leggibilità. Di solito è più facile capire il codice quando i tipi sono scritti.


1

Quando identifichi il tipo rappresentato dalla tua variabile, stai facendo una dichiarazione su un paio di cose. Stai identificando i requisiti di allocazione della memoria per la tua variabile e stai definendo le regole di compatibilità e intervallo per la tua variabile. Fornisce un modo per evitare confusione sulle vostre intenzioni per i dati che state archiviando e per fornirvi un mezzo relativamente economico per identificare potenziali problemi nel codice al momento della compilazione.

Se dichiari le seguenti variabili:

myVar      = 5;
myOtherVar = "C";

Cosa puoi dedurre da queste variabili? È myVarfirmato o non firmato? È a 8 bit, 64 bit o qualcosa nel mezzo? È myOtherVaruna stringa (in modo efficace un array) o un Char? È ANSI o Unicode?

Fornendo tipi di dati specifici, fornisci al compilatore indizi su come può ottimizzare i requisiti di memoria per la tua applicazione. Alcune lingue non si preoccupano molto di questo genere di cose, consentendo di affrontare tali questioni in fase di esecuzione, mentre altre lingue consentono una certa quantità di tipizzazione dinamica perché analizzando il codice è possibile dedurre i tipi di dati.

Un altro punto con linguaggi fortemente tipizzati è che ti evita di dover fornire istruzioni al compilatore ogni volta che usi una variabile. Riesci a immaginare quanto sarebbe orribile e illeggibile il tuo codice se ogni volta che accedi a una variabile, sei stato costretto a lanciarlo efficacemente per dire al compilatore che tipo di valore era? !!


Un buon punto, anche se il compilatore potrebbe semplicemente usare il tipo più efficiente (ad es. Small int) in base al valore, posso vedere che potremmo volere che "C" sia un oggetto stringa piuttosto che char in modo da poter eseguire determinate operazioni . In tali casi, tuttavia, potremmo semplicemente specificare a = (stringa) "C". Questo crea un oggetto stringa e 'a' (variabile non tipizzata) punta semplicemente ad esso. Non lo vedo più orribile della stringa a = "C";
sturdytree,

0

Un programma per computer è un grafico di nodi di processo che descrivono cosa dovrebbe fare una "macchina", rappresentata dal runtime della lingua (esteso con i toolkit nella maggior parte dei casi), in quale ordine o in quali condizioni. Questo grafico è rappresentato da un file di testo (o da un gruppo di file di testo) scritto in una lingua specifica e (parzialmente o completamente) creato quando il compilatore / interprete legge (deserializza) questo file. Inoltre, ci sono alcuni ambienti (UML o strumenti di generazione di programmi grafici) in cui è possibile creare questo grafico e generare il codice sorgente in una lingua di destinazione.

Perché dico questo? Perché questo porta alla risposta alla tua domanda.

Il testo del programma indica le indicazioni su come il computer dovrebbe risolvere l'attività effettiva, contenente sia le fasi del processo (condizioni, azioni) sia la struttura (quali componenti utilizzate nella soluzione). Quest'ultimo significa che puoi ottenere o creare alcune istanze di altri componenti, metterle in caselle denominate (variabili) e usarle: accedi ai loro dati e servizi.

Alcune lingue ti offrono caselle uniformi, in cui è importante solo l'etichetta, ma puoi inserire qualsiasi cosa in esse, puoi persino usare una variabile denominata "target" per memorizzare una "Persona" all'inizio e "Auto" alla fine di lo stesso algoritmo. Altri richiedono la creazione di caselle "sagomate", quindi diverse per una persona o un'automobile, anche se consentono comunque di creare una "scatola generica" ​​(oggetto Java, C / C ++ void *, obiettivo C "id" ...) e lanciarlo come preferisci. I linguaggi tipizzati ti consentono di esprimere la tua struttura con dettagli più precisi, creando "contratti tipo" per le tue variabili (anche se puoi aggirare questa limitazione), mentre i linguaggi non tipizzati supportano questo approccio "Saprò sicuramente cosa ho messo in quella scatola questa volta" come comportamento predefinito e unico.

Entrambi gli approcci sono fattibili, hanno la loro intelligenza del compilatore, molti libri di programmazione, pratiche e framework scritti usando loro (e altre tonnellate di libri su tali framework) su diversi livelli. Quindi oggi la risposta sembra essere più una questione di gusti e di conoscenza del team del programmatore reale che un'affermazione correttamente fondata, misurata e verificata sull'uso o meno dei tipi.

Penso che sia inutile dire che preferisco le regole ai trucchi, specialmente per i progetti a lungo termine di grandi squadre (ovvero: "seri"). Motivo: per quanto ne so, le cause più probabili di un fallimento / slittamento di un progetto SW sono: requisiti poco chiari e cattiva progettazione (80%! Secondo uno studio che conosco), e solo un po 'per cento rimane per l'effettiva codifica. Tutte le regole e i contratti applicano un design più pulito, orientato al futuro e richiedono che le decisioni vengano prese prima e dalle persone giuste. Tipi significano regole: meno "libertà" e "freddezza" - più preparazione, pensiero, standard di codifica, lavoro di squadra controllato. Per me, questo sembra un fattore richiesto di successo, e anche "casa, dolce casa".

I miei 2 centesimi.


-3

AFIAK tutte le lingue con tipizzazione dinamica sono lingue interpretate. Questo è già molto inefficiente, l'aggiunta dell'inefficienza della digitazione dinamica non sarà una grande perdita di tempo. Un linguaggio compilato, tuttavia, non si riferirà effettivamente alle cose per nome quando è in esecuzione. (Escludendo l'uso occasionale di .net reflection o simili - caratteristiche che sono molto lente rispetto al linguaggio sottostante.) La ricerca di tutti quei nomi sarà lenta, lenta, lenta.


3
Sai male. Esistono molti compilatori per linguaggi tipizzati dinamicamente e alcuni di essi sono abbastanza veloci. Gli esempi includono Common Lisp, Scheme ed Erlang.
Ryan Culpepper,

3
Non esiste un "linguaggio interpretato". Una lingua è un insieme astratto di regole matematiche. Una lingua non è né compilata né interpretata. Una lingua è solo. Compilazione e interpretazione sono tratti dell'implementazione, non della lingua. Ogni lingua può essere implementata con un interprete e ogni lingua può essere implementata con un compilatore. E praticamente ogni lingua ha interpretato e compilato entrambe le implementazioni, ad esempio ci sono interpreti per C e compilatori per ECMAScript, Ruby e Python.
Jörg W Mittag,

-4

I linguaggi tipizzati dinamicamente sono spesso propagandati come "orientati agli oggetti". Non sono. Possono essere orientati all'incapsulamento, ma mai orientati agli oggetti. L'orientamento agli oggetti riguarda i tipi.

"Il ragazzo va in bici da suo fratello al negozio di alimentari e acquista una pagnotta dal droghiere". Usando l'orientamento agli oggetti, si può immediatamente scrivere una serie di classi (tipi) per descrivere questo scenario del mondo reale.

In un linguaggio tipizzato in modo dinamico, lo scenario poteva essere rappresentato solo così:

"L'oggetto sposta l'oggetto del suo oggetto sull'oggetto e acquista un oggetto dall'oggetto".

Il potere dell'orientamento agli oggetti è nella sua capacità di modellare il mondo in termini naturali, in modo che lo sviluppatore del software possa usare entrambi i lati del cervello per scrivere software e risolvere i problemi più come essere umano, sia come programmatore di computer. Questo potere è assente nelle lingue tipizzate dinamicamente.

La tipizzazione statica consente una migliore efficienza di codifica, riutilizzabilità e manutenibilità, poiché gli ambienti di sviluppo integrato conoscono i tipi di variabili. Conoscendo i tipi di variabili, un IDE può fornire il completamento automatico in modo che il programmatore non debba fare riferimento alla definizione della classe per ricordare se la proprietà del membro è stata scritta "backlightControl" o "backLightControl" o "bkLightCtrl".

La tipizzazione statica consente il refactoring automatizzato, poiché l'IDE conosce ogni posizione in cui una variabile contiene un'istanza dell'oggetto da refactoring.

La tipizzazione statica consente una maggiore riusabilità e manutenibilità. La digitazione dinamica è migliore per il codice usa e getta. Supponiamo che un nuovo sviluppatore arrivi fuori strada e guardi un pezzo di codice esistente. Se il codice viene digitato staticamente, lo sviluppatore può, con due clic del mouse, esaminare la definizione di classe di ciascuna delle variabili coinvolte, sapere a cosa serve la classe, sapere quali altri metodi e proprietà sono disponibili. Se il codice viene digitato in modo dinamico, lo sviluppatore deve utilizzare la ricerca globale per capire cosa sta succedendo.


2
Temo di non essere d'accordo con te sulla prima parte della tua discussione. I linguaggi tipizzati dinamicamente sono generalmente "orientati agli oggetti", ma non "orientati alla classe". Questa è una distinzione importante. Nel tuo esempio, in realtà stai vivendo in un'illusione. Puoi avere una Boylezione, ma dubito che possa fare tutto ciò che fa un "ragazzo" nel mondo reale. Tuttavia, nel tuo esempio dinamico (L'oggetto cavalca ...), sappiamo l'unica cosa importante di questo oggetto "ragazzo": può cavalcare . Questa è la filosofia di base dei linguaggi di tipo dinamico. Ha + ve s e -ve s. Quale ti piace è la tua opinione.
Chip
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.