2009-11-11 6 views
14

Mi sono imbattuto in this question nelle Domande frequenti su Go e mi ha ricordato qualcosa che mi ha infastidito per un po '. Sfortunatamente, non vedo veramente a che cosa arrivi la risposta.Perché molti linguaggi di programmazione inseriscono il tipo * dopo * il nome della variabile?

sembra che quasi tutte le lingue non C-come mette il tipo dopo il nome della variabile, in questo modo:

var : int 

Solo per pura curiosità, perché è questo? Ci sono dei vantaggi nello scegliere l'uno o l'altro?

+0

@Jurily - non voglio contestare questo. Ero solo curioso di sapere se c'era qualche vantaggio nel fare le cose in un modo o in un altro. –

+3

@Jurily, per essere precisi, _everyone_ ha il loro ultimo cognome :-). E per essere onesti, penso che se la maggior parte delle persone dovesse guardarlo in modo imparziale, concorderebbero sul fatto che l'approccio generale a specifico (come in cinese o, come dici tu, ungherese) ha più senso. –

+0

https://stackoverflow.com/questions/1891775/any-reason-for-having-val-capacity-int-instead-of-val-int-capacity-in-scal/1893263 – starblue

risposta

12

C'è un problema di analisi, come dice Keith Randall, ma non è quello che descrive. Il "non sapere se si tratta di una dichiarazione o di un'espressione" semplicemente non ha importanza - non ti importa se si tratta di un'espressione o di una dichiarazione finché non hai comunque analizzato l'intera faccenda, a quel punto l'ambiguità viene risolta.

Utilizzando un parser senza contesto, non importa se il tipo viene prima o dopo il nome della variabile. Ciò che conta è che non è necessario cercare i nomi dei tipi definiti dall'utente per comprendere le specifiche del tipo - non è necessario aver capito tutto ciò che è venuto prima per comprendere il token corrente.

La sintassi di Pascal è senza contesto - se non completamente, almeno WRT questo problema. Il fatto che il nome della variabile venga prima è meno importante dei dettagli come il separatore dei due punti e la sintassi delle descrizioni dei tipi.

La sintassi C è sensibile al contesto.Affinché il parser determini dove termina una descrizione del tipo e quale token è il nome della variabile, è necessario aver già interpretato tutto ciò che è venuto prima in modo che possa determinare se un determinato token identificativo è il nome della variabile o solo un altro token che contribuisce a la descrizione del tipo.

Poiché la sintassi C è sensibile al contesto, è molto difficile (se non impossibile) analizzare utilizzando strumenti di parser-generator tradizionali come yacc/bison, mentre la sintassi di Pascal è facile da analizzare utilizzando gli stessi strumenti. Detto questo, ora ci sono i generatori di parser che possono far fronte alla sintassi C e persino al C++. Anche se non è correttamente documentato o in un 1.? rilascio ecc., il mio preferito è Kelbt, che usa il backtracking di LR e supporta il semantico "annulla" - fondamentalmente annullando aggiunte alla tabella dei simboli quando le analisi speculative risultano errate.

In pratica, i parser C e C++ sono in genere scritti a mano, mescolando la discesa ricorsiva e l'analisi della precedenza. Presumo lo stesso vale per Java e C#.

Per inciso, problemi simili con la sensibilità al contesto nell'analisi in C++ hanno creato molti problemi. Il "Alternative Function Syntax" per C++ 0x sta lavorando a un problema simile spostando una specifica di tipo alla fine e posizionandola dopo un separatore - molto simile ai due punti Pascal per i tipi di ritorno di funzione. Non elimina la sensibilità al contesto, ma l'adozione di tale convenzione tipo Pascal lo rende un po 'più gestibile.

+0

* EDIT * - confession - con discesa ricorsiva, * è * un po 'più facile da analizzare se il costrutto è facilmente identificabile vicino al suo inizio. Avere una parola chiave vicino all'inizio è buona. In realtà non contiamo il nome-tipo-variabile-C in questo modo, perché in realtà non identifica il costrutto prima della variabile-poi-tipo. Potrebbe essere una dichiarazione di variabile - o una dichiarazione di funzione, o di uno stile di funzione di typecast su una variabile a sinistra-mano-lato di una cessione, o ... – Steve314

+0

Non è presente più di una funzione del colon però ? Come posso dire che 'var: int' è un nome di variabile a causa dei due punti. Sembra che sarebbe altrettanto facile fare 'int: var' (anche se forse un po 'più brutto :-)). –

+1

@Jason Baker - scusa per il ritardo. Un compilatore può gestire "varname int" o "int varname", assumendo che "int" sia una parola chiave. Tuttavia, "varname mytype" o "mytype varname" è più un problema - non perché "mytype" sia esattamente un identificatore, ma perché è necessario cercare nel dizionario per determinare quali costrutti sintattici potrebbero applicarsi. La vecchia sintassi C in cui i nomi delle struct non erano nomi di caratteri validi (si scriveva "struct structname myvar;") era più semplice, poiché quel prefisso "struct" mostra sintatticamente che il tipo * è * un tipo. Un colon può aiutare, ma non è né l'insieme né l'unica soluzione. – Steve314

1

È proprio come è stato progettato il linguaggio. Visual Basic è sempre stato così.

La maggior parte (se non tutte) le lingue di parentesi graffe mette il tipo prima. Questo è più intuitivo per me, poiché la stessa posizione specifica anche il tipo di ritorno di un metodo. Quindi gli input vanno nella parentesi e l'output esce dal retro del nome del metodo.

+4

laguages ​​che mettono l'ultimo tipo anche mettere il tipo di ritorno scorso, ad esempio nome (arg: tipo): return_type –

+0

C++ 0x consente di mettere il tipo di ritorno della funzione scorso: 'func automatico (int arg1) -> int' – jmucchiello

10

le "molte altre lingue" di cui parli sono quelle che sono più dichiarative. Mirano a permetterti di programmare di più lungo le linee in cui pensi (assumendo che non sei inscatolato nel pensiero imperativo).

tipo ultima recita 'creare una variabile denominata NOME di tipo TIPO'

questo è l'opposto, naturalmente, per dire 'creare un tipo chiamato NAME', ma quando si pensa a questo proposito, che cosa il valore è per è più importante del tipo, il tipo è semplicemente un vincolo programmatico sui dati

+1

+1 ben detto ... e 15 personaggi in più. – wheaties

1

Non sono sicuro, ma penso che abbia a che fare con il concetto "nome contro nome".

In sostanza, se si inserisce il tipo per primo (come "int varname"), si dichiara un "intero denominato" varname ""; cioè, stai dando un'istanza di un tipo a un nome. Tuttavia, se metti prima il nome e poi il tipo (come "varname: int"), stai dicendo "questo è 'varname', è un numero intero". Nel primo caso, stai dando un'istanza di qualcosa di un nome; nel secondo, stai definendo un nome e affermando che si tratta di un'istanza di qualcosa.

È un po 'come se si stesse definendo un tavolo come un mobile; dicendo "questo è il mobile e io lo chiamo 'tavolo'" (tipo prima) è diverso dal dire "un tavolo è un tipo di mobile" (tipo ultimo).

0

Inserire il tipo aiuta prima nell'analisi. Per esempio, in C, se dichiarato variabili come

x int; 

quando si analizza solo il x, allora non si sa se x è una dichiarazione o di un'espressione. Al contrario, con

int x; 

quando si analizza il int, sai che sei in una dichiarazione (tipi iniziano sempre una dichiarazione di qualche tipo).

Dato il progresso nell'analisi delle lingue, questo leggero aiuto non è terribilmente utile al giorno d'oggi.

+1

Se la facilità di analisi è il vostro obiettivo, si avrebbe una parola chiave che introduce tutte le dichiarazioni di variabili, come ad esempio var: 'var i: int' o' var int I' – jmucchiello

+0

E per i tipi definiti dall'utente (typedef): abc xyz; - qual è il tipo e qual è il nome? Finché la lingua è d'accordo sulle regole, non c'è un problema - e se la lingua non può essere d'accordo sulle regole, probabilmente non è analizzabile. –

-3

Che dire di dinamicamente (cheers @wcoenen) lingue digitate? Devi solo usare la variabile.

+8

Vuoi dire "digitato dinamicamente". "weakly vs fortemente typed" non è la stessa distinzione di "statically vs typed in modo dinamico". Ad esempio, pitone è la lingua in modo dinamico e fortemente tipizzato: http://wiki.python.org/moin/Why%20is%20Python%20a%20dynamic%20language%20and%20also%20a%20strongly%20typed%20language –

+0

debolmente lingue digitato come awk o (vecchio) Perl; o Fortran con le sue variabili implicitamente tipizzate - i nomi che iniziano con I fino a N sono interi; il resto è REALE. –

7

Se il nome della variabile inizia dalla colonna 0, è più semplice trovare il nome della variabile.

Confronta

QHash<QString, QPair<int, QString> > hash; 

e

hash : QHash<QString, QPair<int, QString> >; 

Ora immaginate quanta più leggibile l'intestazione tipico C++ potrebbe essere.

+0

Il nome +1 è più leggibile, ti induce a capire che cosa sta agendo immediatamente per la dichiarazione ... presumendo ovviamente che stai usando nomi di variabili significativi. – bobince

6

Nella teoria dei linguaggi formali e nella teoria dei tipi, è quasi sempre scritto come var: type. Ad esempio, nel lambda calcolo tipizzato vedrete prove contenente affermazioni quali:

x : A y : B 
------------- 
\x.y : A->B 

Non credo che è importante, ma penso che ci sono due giustificazioni: uno è che "x: A" viene letto "x è di tipo A", l'altro è che un tipo è come un set (ad esempio int è l'insieme di numeri interi) e la notazione è correlata a "x ε A".

Alcune di queste cose sono pre-date alle lingue moderne a cui stai pensando.

8

Una tendenza crescente è quella di non indicare affatto il tipo o di specificare opzionalmente il tipo. Questo potrebbe essere un langauge tipizzato dinamicamente dove non c'è davvero alcun tipo sulla variabile, o potrebbe essere un linguaggio tipizzato staticamente che ne deduce il tipo dal contesto.

Se il tipo viene talvolta indicato e talvolta dedotto, è più semplice leggere se il bit opzionale viene in seguito.

Ci sono anche tendenze relative al fatto che una lingua si consideri come proveniente dalla scuola C o dalla scuola funzionale o altro, ma queste sono una perdita di tempo. Le lingue che migliorano i loro predecessori e che valgono la pena di essere apprese sono quelle che sono disposte ad accettare input da tutte le diverse scuole in base al merito, non essere pignoli sul patrimonio di una caratteristica.

0

Fortran mette il tipo di prima:

REAL*4 I,J,K 
INTEGER*4 A,B,C 

E sì, c'è una (molto debole) scherzo lì per chi ha familiarità con Fortran.

C'è spazio per sostenere che questo è più semplice di C, che mette le informazioni sul tipo attorno al nome quando il tipo è abbastanza complesso (puntatori alle funzioni, ad esempio).

+0

Hai inventato FORTRAN offuscato. Molto bene. – jmucchiello

1

Ho sempre pensato che il modo in cui lo fa fosse un po 'strano: invece di costruire tipi, l'utente deve dichiararli implicitamente. Non è solo prima/dopo il nome della variabile; in generale, potrebbe essere necessario incorporare il nome della variabile tra gli attributi di tipo (o, in alcuni casi, per incorporare uno spazio vuoto in cui il nome corrisponderebbe a se in realtà ne stai dichiarando uno).

Come una forma debole di corrispondenza del modello, è intelligibile in una certa misura, ma non sembra fornire alcun vantaggio particolare, sia. E, provare a scrivere (o leggere) un tipo di puntatore a funzione può facilmente portarti oltre il punto di intelligibilità pronta. Quindi, in generale, questo aspetto di C è uno svantaggio, e sono felice di vedere che Go ha lasciato indietro.

4

"Coloro che non ricordano il passato sono condannati a ripeterlo."

Inserire il tipo prima che la variabile iniziasse in modo innocuo con Fortran e Algol, ma è diventato davvero brutto in C, dove alcuni tipi di modificatori vengono applicati prima della variabile, altri dopo. Ecco perché in C si dispone di tali bellezze come

int (*p)[10]; 

o

void (*signal(int x, void (*f)(int)))(int) 

insieme ad un programma di utilità (cdecl) il cui scopo è quello di decifrare quali senza senso.

In Pascal, il tipo viene dopo la variabile, in modo che i primi esempi diventa

p: pointer to array[10] of int 

contrasto con

q: array[10] of pointer to int 

che, in C, è

int *q[10] 

In C , hai bisogno di parentesi per distinguere questo da int (* p) [10]. Le parentesi non sono richieste in Pascal, dove conta solo l'ordine.

La funzione segnale sarebbe

signal: function(x: int, f: function(int) to void) to (function(int) to void) 

Ancora un sorso, ma almeno all'interno del regno della comprensione umana.

In tutta onestà, il problema non è che C metta il tipo prima del nome, ma che insiste perversamente sul mettere prima i pezzi, e altri dopo, il nome.

Ma se si tenta di mettere tutto ciò che prima del nome, l'ordine è ancora poco intuitivo:

int [10] a // an int, ahem, ten of them, called a 
int [10]* a // an int, no wait, ten, actually a pointer thereto, called a 

Quindi, la risposta è: Un linguaggio di programmazione sensibilmente progettato mette le variabili prima che i tipi perché il risultato è più leggibile per gli umani.

Problemi correlati