Perché i nomi delle variabili non possono iniziare con i numeri?

Stavo lavorando con un nuovo sviluppatore c ++ qualche tempo fa quando ha posto la domanda: “Perché i nomi delle variabili non possono iniziare con i numeri?”

Non sono riuscito a trovare una risposta se non che alcuni numeri possono contenere del testo (123456L, 123456U) e che non sarebbe ansible se i compilatori pensassero che tutto con una certa quantità di caratteri alfa fosse un nome di variabile.

Era quella la risposta giusta? Ci sono altri motivi?

string 2BeOrNot2Be = "that is the question"; // Why won't this compile? 

Perché quindi una stringa di cifre sarebbe un identificatore valido e un numero valido.

 int 17 = 497; int 42 = 6 * 9; String 1111 = "Totally text"; 

Bene pensa a questo:

 int 2d = 42; double a = 2d; 

Cos’è un? 2.0? o 42?

Suggerimento, se non lo ottieni, d dopo un numero indica il numero prima che sia un doppio letterale

È una convenzione ora, ma è iniziata come requisito tecnico.

In passato, i parser di linguaggi come FORTRAN o BASIC non richiedevano l’uso degli spazi. Quindi, fondamentalmente, i seguenti sono identici:

 10 V1=100 20 PRINT V1 

e

 10V1=100 20PRINTV1 

Supponiamo ora che fossero ammessi prefissi numerici. Come interpreteresti questo?

 101V=100 

come

 10 1V = 100 

o come

 101 V = 100 

o come

 1 01V = 100 

Quindi, questo è stato reso illegale.

Perché il backtracking è evitato nell’analisi lessicale durante la compilazione. Una variabile come:

 Apple; 

il compilatore saprà che è un identificatore subito quando incontra la lettera “A”.

Tuttavia una variabile come:

 123apple; 

il compilatore non sarà in grado di decidere se si tratta di un numero o di un identificatore fino a quando non raggiunge “a”, e di conseguenza ha bisogno di un backtracking.

Compilatori / parser / analizzatori lessicali è stato molto, molto tempo fa per me, ma penso di ricordare che ci sono difficoltà nel determinare senza ambiguità se un carattere numerico nell’unità di compilazione rappresenta un letterale o un identificatore.

Le lingue in cui lo spazio è insignificante (come ALGOL e FORTRAN originale se ricordo male) non potevano accettare numeri per iniziare identificatori per quel motivo.

Questo va molto indietro – prima delle notazioni speciali per indicare memoria o base numerica.

È probabile che sia stata presa una decisione per alcuni motivi, quando stai analizzando il token devi solo guardare il primo carattere per determinare se si tratta di un identificativo o letterale e quindi inviarlo alla funzione corretta per l’elaborazione. Questa è un’ottimizzazione delle prestazioni.

L’altra opzione sarebbe quella di verificare se non è un valore letterale e lasciare che il dominio degli identificatori sia l’universo meno i letterali. Ma per farlo dovresti esaminare ogni personaggio di ogni token per sapere come classificarlo.

Ci sono anche implicazioni stilistiche che gli identificatori dovrebbero essere mnemonici, quindi le parole sono molto più facili da ricordare rispetto ai numeri. Quando sono state scritte molte delle lingue originali impostando gli stili per i prossimi decenni, non stavano pensando di sostituire “2” per “a”.

Sono d’accordo che sarebbe utile consentire agli identificatori di iniziare con una cifra. Una o due persone hanno detto che è ansible aggirare questa restrizione anteponendo un trattino basso all’identificatore, ma questo è davvero brutto.

Penso che parte del problema derivi da numeri letterali come 0xdeadbeef, che rendono difficile trovare regole facili da ricordare per gli identificatori che possono iniziare con una cifra. Un modo per farlo potrebbe essere quello di consentire qualsiasi cosa che corrisponda a [A-Za-z _] + che NON sia una parola chiave o un numero letterale. Il problema è che potrebbe portare a cose strane come 0xdeadpork essere consentito, ma non 0xdeadbeef. In definitiva, penso che dovremmo essere onesti con tutte le carni: P.

Quando stavo imparando per la prima volta C, ricordo di aver sentito che le regole per i nomi delle variabili erano arbitrarie e restrittive. Peggio ancora, erano difficili da ricordare, quindi ho rinunciato a cercare di impararli. Ho appena fatto quello che mi sembrava giusto, e ha funzionato abbastanza bene. Ora che ho imparato molto di più, non sembra così male, e alla fine ho imparato a impararlo nel modo giusto.

L’uso di una cifra per iniziare un nome di variabile rende molto più complicato il controllo degli errori durante la compilazione o l’interpertazione.

Consentire l’uso di nomi variabili iniziati come un numero probabilmente causerebbe enormi problemi ai progettisti di linguaggi. Durante l’analisi del codice sorgente, ogni volta che un compilatore / interprete incontrava un token che iniziava con una cifra in cui era previsto un nome di variabile, doveva cercare attraverso un insieme di regole enorme e complicato per determinare se il token fosse realmente una variabile o un errore . La complessità aggiunta aggiunta al parser della lingua potrebbe non giustificare questa funzione.

Fin da quando riesco a ricordare (circa 40 anni), non penso di aver mai usato un linguaggio che permettesse l’uso di una cifra per iniziare nomi di variabili. Sono sicuro che questo è stato fatto almeno una volta. Forse, qualcuno qui ha effettivamente visto questo da qualche parte.

Come molte persone hanno notato, c’è un sacco di bagagli storici sui formati validi per i nomi delle variabili. E i designer di lingue sono sempre influenzati da ciò che sanno quando creano nuove lingue.

Detto questo, praticamente tutto il tempo in cui una lingua non consente ai nomi delle variabili di iniziare con i numeri è perché quelle sono le regole del design del linguaggio. Spesso è perché una regola così semplice rende l’analisi e il lessico della lingua molto più facile. Tuttavia, non tutti i progettisti di lingue sanno che questa è la vera ragione. I moderni strumenti di lexing aiutano, perché se provassi a definirlo come permesso, ti daranno dei conflitti di analisi.

OTOH, se la tua lingua ha un carattere identificabile in modo univoco per annotare i nomi delle variabili, è ansible impostarle affinché inizino con un numero. È ansible utilizzare anche varianti di regole simili per consentire spazi nei nomi di variabili. Ma è probabile che il linguaggio risultante non assomigli molto a qualsiasi linguaggio convenzionale popolare, se non del tutto.

Per un esempio di un linguaggio di template HTML abbastanza semplice che consente alle variabili di iniziare con i numeri e di avere spazi incorporati, guarda su Qompose .

Perché se hai permesso che la parola chiave e l’identificatore iniziassero con caratteri numerici, il lexer (parte del compilatore) non poteva facilmente distinguere tra l’inizio di un valore letterale numerico e una parola chiave senza diventare molto più complicato (e più lento).

La restrizione è arbitraria. Vari Lisps consentono ai nomi dei simboli di iniziare con i numeri.

I nomi delle variabili non possono iniziare con una cifra, perché possono causare alcuni problemi come quelli seguenti:

 int a = 2; int 2 = 5; int c = 2 * a; 

qual è il valore di c? è 4, o è 10!

un altro esempio:

 float 5 = 25; float b = 5.5; 

è il primo 5 un numero, o è un object (operatore.) C’è un problema simile con il secondo 5.

Forse, ci sono altri motivi. Quindi, non dovremmo usare nessuna cifra all’inizio di un nome di variabile.

COBOL consente alle variabili di iniziare con una cifra.

C ++ non può averlo perché i progettisti linguistici ne hanno fatto una regola. Se dovessi creare la tua lingua, potresti certamente permetterlo, ma probabilmente incontrerai gli stessi problemi che hanno fatto e deciderai di non permetterlo. Esempi di nomi di variabili che potrebbero causare problemi:

0x, 2d, 5555

Uno dei problemi chiave del rilassamento delle convenzioni sintattiche è che introduce una dissonanza cognitiva nel processo di codifica. Il modo in cui pensi al tuo codice potrebbe essere profondamente influenzato dalla mancanza di chiarezza che ciò introdurrebbe.

Dykstra non ha detto che “l’aspetto più importante di qualsiasi strumento è il suo effetto sul suo utente”?

Probabilmente perché rende più facile all’essere umano dire se si tratta di un numero o di un identificatore, e per via della tradizione. Avere identificatori che potrebbero iniziare con una cifra non complicherebbe più di tanto le scansioni lessicali.

Non tutte le lingue hanno gli identificatori vietati che iniziano con una cifra. In Forth, potevano essere numeri, e piccoli interi erano normalmente definiti come parole Forth (essenzialmente identificatori), poiché era più veloce leggere “2” come una routine per spingere un 2 nello stack piuttosto che riconoscere “2” come numero il cui valore era 2. (Nell’elaborare l’input dal programmatore o dal blocco del disco, il sistema Forth avrebbe diviso l’input in base agli spazi, cercando di visualizzare il token nel dizionario per vedere se era una parola definita, e in caso contrario, tenterebbe di tradurlo in un numero, e in caso contrario segnalerebbe un errore.)

Supponiamo di aver permesso che i nomi dei simboli iniziassero con i numeri. Supponiamo ora di voler nominare una variabile 12345foobar. Come distingueresti questo dal 12345? In realtà non è terribilmente difficile da fare con un’espressione regolare. Il problema è in realtà una delle prestazioni. Non posso davvero spiegare perché questo è molto dettagliato, ma in sostanza si riduce al fatto che la differenziazione 12345foobar dal 12345 richiede il backtracking. Ciò rende l’espressione regolare non deterministica.

C’è una spiegazione molto migliore di questo qui .

è facile per un compilatore identificare una variabile usando ASCII nella posizione di memoria anziché nel numero.

Penso che la risposta semplice sia che può, la restrizione è basata sul linguaggio. In C ++ e molti altri non può perché il linguaggio non lo supporta. Non è incorporato nelle regole per consentirlo.

La domanda è come chiedere perché il Re non può muovere quattro spazi alla volta a scacchi? È perché a scacchi è una mossa illegale. Può in un altro gioco sicuro. Dipende solo dalle regole in gioco.

Originariamente era semplicemente perché è più facile ricordare (si può dare più significato) nomi di variabili come stringhe piuttosto che numeri, sebbene i numeri possano essere inclusi all’interno della stringa per migliorare il significato della stringa o consentire l’uso dello stesso nome di variabile ma averlo designato come un significato o contesto separato, ma vicino. Ad esempio, loop1, loop2 etc ti farebbero sempre sapere che eri in un loop e / o il loop 2 era un loop all’interno di loop1. Quale preferiresti (ha più significato) come variabile: indirizzo o 1121298? Quale è più facile da ricordare? Tuttavia, se la lingua usa qualcosa per indicare che non solo testo o numeri (come l’indirizzo $ in $) in realtà non dovrebbe fare la differenza, poiché ciò direbbe al compilatore che quanto segue deve essere trattato come una variabile ( in questo caso). In ogni caso si tratta di ciò che i designer di linguaggio vogliono usare come regole per la loro lingua.

La variabile può essere considerata come un valore anche durante il tempo di compilazione dal compilatore in modo che il valore possa chiamare il valore ancora e ancora ricorsivamente

Il backtracking è evitato nella fase di analisi lessicale mentre si compila il pezzo di codice . La variabile come Apple; , il compilatore conoscerà immediatamente un identificatore quando incontra il carattere di lettera “A” nella fase di analisi lessicale. Tuttavia, una variabile come 123apple; , il compilatore non sarà in grado di decidere se è un numero o identificatore fino a quando non colpisce ‘a’ e ha bisogno di tornare indietro nella fase di analisi lessicale per identificare che si tratta di una variabile. Ma non è supportato nel compilatore.

Riferimento

Il compilatore ha 7 fasi come segue:

  1. Analisi lessicale
  2. Analisi della syntax
  3. Analisi semantica
  4. Generazione di codice intermedio
  5. Ottimizzazione del codice
  6. Generazione del codice
  7. Tabella dei simboli

Il backtracking viene evitato nella fase di analisi lessicale mentre si compila il pezzo di codice. La variabile come Apple, il compilatore conoscerà immediatamente un identificatore quando incontra il carattere di lettera “A” nella fase di analisi lessicale. Tuttavia, una variabile come 123apple, il compilatore non sarà in grado di decidere se è un numero o identificatore fino a quando non colpisce ‘a’ e ha bisogno di tornare indietro nella fase di analisi lessicale per identificare che si tratta di una variabile. Ma non è supportato nel compilatore.

Quando stai analizzando il token, devi solo guardare il primo carattere per determinare se si tratta di un identificatore o di un letterale e quindi inviarlo alla funzione corretta per l’elaborazione. Questa è un’ottimizzazione delle prestazioni.

Non ci potrebbe essere nulla di sbagliato quando si tratta di dichiarare la variabile. Ma c’è qualche ambiguità quando tenta di usare quella variabile da qualche altra parte in questo modo:

let 1 = “Ciao mondo!” stampa (1) stampa (1)

print è un metodo generico che accetta tutti i tipi di variabile. quindi in quella situazione il compilatore non sa a quale (1) si riferisce il programmatore: il 1 del valore intero o il 1 che memorizza un valore stringa. forse meglio per il compilatore in questa situazione per permettere di definire qualcosa del genere ma quando si cerca di usare questa roba ambigua, portare un errore con capacità di correzione su come sistemare quell’errore e cancellare questa ambiguità.