Perché la maggior parte dei linguaggi di programmazione non annidano i commenti a blocchi?


18

Alcuni lo fanno, ma non quelli popolari per quanto ne so. C'è qualcosa di brutto nel annidare i commenti?

Ho intenzione di far annidare i commenti a blocchi nella (piccola) lingua su cui sto lavorando, ma vorrei sapere se questa è una cattiva idea.


re alcune risposte: ohh, questo ha senso =) Sto facendo totalmente commenti a blocchi nidificati allora; sebbene io abbia uno stadio lexing separato, non è il tipo limitante di logica SK descritta.

@Vuntic: se hai una fase di lexing separata che usa cose più complicate delle espressioni regolari, potresti avere problemi di prestazioni. Le RE sono veloci e facili da usare implementando i DFA.
David Thornley,


4
@ David: ... per niente. In realtà è davvero veloce.
Amara,

Vorrei suggerire che se si desidera consentire commenti nidificati, è possibile contrassegnare i tag di commento iniziale con un token e richiedere che se un tag di commento iniziale è così contrassegnato, il tag di commento finale deve essere contrassegnato in modo identico. Ciò consentirebbe di identificare rapidamente i tag di inizio / fine non bilanciati ed evitare la possibilità di errori causati da tag non bilanciati non rilevati.
supercat,

Risposte:


6

Una cosa che nessuno ha ancora menzionato, quindi lo menzionerò: il desiderio di annidare i commenti spesso indica che il programmatore sta facendo qualcosa di sbagliato.

Innanzitutto, concordiamo sul fatto che l'unica volta che "annidamento" o "non annidamento" è visibile al programmatore è quando il programmatore scrive qualcosa di strutturalmente come questo:

do_something();
/* comment /* nested comment */ more comment */
do_something_else();

Ora, quando succede una cosa del genere in pratica? Certamente il programmatore non scriverà commenti nidificati che assomigliano letteralmente allo snippet sopra! No, in pratica quando annidiamo i commenti (o vorremmo poterli annidare), è perché vogliamo scrivere qualcosa del genere:

do_something();  /* do a thing */
/* [ajo] 2017-12-03 this turned out to be unnecessary
do_something_else(); /* do another thing */
*/

E questo è MALE. Questo non è uno schema che noi (come designer linguistici) vogliamo incoraggiare! Il modo corretto di scrivere lo snippet sopra è:

do_something();  /* do a thing */

Quel codice "sbagliato", quel falso inizio o qualunque cosa fosse, non appartiene alla base di codice. Appartiene, nella migliore delle ipotesi, alla storia del controllo del codice sorgente. Idealmente, non avresti mai nemmeno scritto il codice sbagliato, giusto? E se il codice sbagliato stava servendo uno scopo lì, avvertendo i manutentori di non ripristinarlo per qualche motivo, beh, probabilmente è un lavoro per un commento di codice ben scritto e intenzionale. Cercare di esprimere "non fare X" semplicemente lasciando un vecchio codice che fa X, ma commentato, non è il modo più leggibile o efficace per impedire alle persone di fare X.

Tutto questo si riduce a una semplice regola empirica che potresti aver sentito prima: non commentare il codice. (Ricerca di questa frase si accende un sacco di opinioni in accordo .)

Prima di chiedere: sì, linguaggi come C, C # e C ++ già danno il programmatore un'altra strumento per "commentate" grandi blocchi di codice: #if 0. Ma questa è solo una particolare applicazione del preprocessore C, che è uno strumento ampio e utile a sé stante. In realtà sarebbe estremamente difficile e speciale per un linguaggio supportare la compilazione condizionale #ife tuttavia non supportarla #if 0.


Quindi, abbiamo stabilito che i commenti nidificati sono rilevanti solo quando il programmatore sta commentando il codice; e abbiamo stabilito (tramite il consenso di molti programmatori esperti) che commentare il codice è una cosa negativa.

Per completare il sillogismo, dobbiamo accettare che i progettisti linguistici hanno interesse a promuovere le cose buone e scoraggiare le cose cattive (supponendo che tutto il resto sia uguale).

Nel caso di commenti nidificati, tutto il resto è uguale: puoi tranquillamente ignorare le risposte a basso voto che sostengono che l'analisi del nidificato /*sarebbe in qualche modo "difficile" per il parser. (I nidificati /*non sono più difficili di quelli nidificati (, che quasi tutti i parser al mondo devono già gestire.)

Quindi, a parità di tutto il resto, un progettista di lingue dovrebbe rendere facile annidare i commenti (ovvero commentare il codice) o difficile? Ricorda che commentare il codice è una cosa negativa.

QED


Nota. Nota che se non consenti commenti nidificati, allora

hello /* foo*/bar.txt */ world

è un "commento" fuorviante - equivale a

hello bar.txt */ world

(che è probabilmente un errore di sintassi). Ma se si fa permettono commenti nidificati, quindi

hello /* foo/*.txt */ world

è un "commento" fuorviante - equivale a

hello

ma lascia il commento aperto fino alla fine del file (che di nuovo è quasi certamente un errore di sintassi). Quindi nessuno dei due modi è particolarmente meno soggetto a errori di sintassi involontari. L'unica differenza sta nel modo in cui gestiscono l' antipasto intenzionale del codice commentato.


1
Ho un'opinione diversa basata sul semplice fatto: non ho visto tutto (e nemmeno tu). Quindi, mentre quelle regole d'oro come "Non commentare il codice" sembrano belle, la vita ha i suoi percorsi. In questo caso particolare, lo faccio molto spesso come switch, quando collaudo alcune nuove funzionalità e devo introdurre in modo incrementale del codice, quindi commento il codice, quindi meno, meno, meno, e finalmente ho un pezzo funzionante e io può rimuovere tutti i commenti (sopra il codice). Il mio linguaggio perfetto supporterà ovviamente i commenti nidificati :-).
Greenoldman,

@greenoldman: la maggior parte delle lingue non ha commenti annidabili, ma avranno alcune funzionalità effettive per "rimuovere un blocco di codice" che è meno utilizzato rispetto alla funzione "lascia un commento". C #if DEADè l'esempio canonico e meglio progettato. In molte lingue puoi semplicemente racchiudere il codice morto nell'equivalente di if (DEAD). E in molti IDE, puoi effettivamente rimuovere il codice morto e fare affidamento su Ctrl + Z e / o controllo versione per recuperarlo se lo desideri. Lasciare un commento, dotstring, qualunque cosa, il cui testo è un mucchio di codice morto, è ancora l' opzione peggiore per la leggibilità.
Quuxplusone,

11

Poiché la maggior parte delle implementazioni utilizza lexing separate e fasi di analisi e per il lexing usano semplici espressioni regolari. I commenti vengono trattati come spazi bianchi, ovvero token ignorati, e quindi devono essere risolti interamente in un passaggio lexing. L'unico vantaggio di questo approccio è l'analisi della velocità. Numerosi svantaggi includono gravi limitazioni alla sintassi (ad esempio, la necessità di mantenere un insieme fisso di parole chiave indipendenti dal contesto).


3
Non sarei d'accordo su "quasi" al giorno d'oggi. Certamente questo è il modo tradizionale, ma so che per C, EDG combina il preprocessore, il lexing e l'analisi, e sospetto che lo facciano anche GCC e Microsoft. Il vantaggio è che ti consente di implementarli separatamente, se necessario.
Andrew Aylett,

Anche Clang sta facendo lo stesso. Ma questa è ancora solo una piccola parte dei compilatori di lingue popolari esistenti.
SK-logic

@Neil Butterworth, dai un'occhiata a mcs, javac, gcc (sì, esegue il back-patch di un lexer, ma è comunque un lexing pass dedicato), clang (come gcc), dmd, fpc e molti altri.
SK-logic

Nessuno sta usando espressioni regolari nel proprio lexing per qualsiasi compilatore non banale.
Nuoji,

@Nuoji - per il non banale - certo. Ma quelli che si affidano alla flessibilità e strumenti simili lo fanno.
SK-logic

7

È perfettamente possibile creare un lexer in grado di gestire i commenti nidificati. Quando consuma spazi bianchi, quando vede /*può aumentare un contatore di profondità e diminuirlo quando vede */, e fermarsi quando la profondità è zero. Detto questo, ho fatto molti parser e non ho mai trovato una buona ragione per annidare i commenti.

Se i commenti possono essere nidificati, allora un aspetto negativo è che è facile bilanciare i loro fini e, a meno che tu non abbia un editor sofisticato, può nascondere invisibilmente il codice che presumi sia lì.

Un lato positivo dei commenti che non nidificano è qualcosa del genere:

/*
some code
more code
blah blah blah
/**/

dove puoi facilmente commentare dentro o fuori il codice rimuovendo o aggiungendo la prima riga - una modifica di 1 riga. Naturalmente, se quel codice stesso contiene un commento, questo si spezzerebbe, a meno che tu non autorizzi anche //commenti in stile C ++ . Quindi è quello che tendo a fare.


1
//i commenti sono anche in stile C99.
JAB,

In alternativa, una lingua potrebbe specificare l'inizio di un commento /*$token, dov'è identifierqualsiasi token alfanumerico, e la fine del commento è token$*/. Sarebbe relativamente semplice per il tokenizer includere il codice per verificare che ogni segno di commento finale contenga il token corretto per il blocco corrispondente di commento iniziale.
supercat,

5

Poiché nessun altro lo ha menzionato, elencherò alcune lingue che supportano i commenti nidificati: Rexx, Modula-2, Modula-3, Oberon. Nonostante tutte le lamentele qui per problemi di velocità e difficoltà, nessuno di questi sembra avere problemi enormi.


4
A cui aggiungo: Haskell, Frege
Ingo,

Supportato anche da Scala.
Matt R

4

Un buon punto per annidare i commenti di blocco è che puoi commentare facilmente grandi porzioni di codice (beh, quasi, a meno che tu non abbia la sequenza finale dei commenti di blocco in una costante di stringa).

Un metodo alternativo è anteporre un gruppo di righe con la sequenza di inizio dei commenti di riga se si dispone di un editor che lo supporta.

Haskell ha annidato i commenti in blocco, ma la maggior parte delle persone non sembra accorgersene o lamentarsene. Immagino che ciò sia dovuto al fatto che le persone che non si aspettano commenti nidificati tendono ad evitarli in quanto questo sarebbe un errore lessicale in altre lingue.


3

Il supporto dei commenti a blocchi nidificati complica il parser, che è sia più lavoro che potrebbe aumentare il tempo di compilazione. Immagino che non sia una funzionalità molto necessaria per una lingua, quindi è meglio usare il tempo e gli sforzi su altri miglioramenti e ottimizzazioni.

Secondo me la semplicità è sempre una buona cosa nel progettare qualcosa. Tieni presente che è più semplice aggiungere una funzionalità che rimuoverla. Una volta che permetti i commenti nidificati e ci sono programmi là fuori che lo utilizzano, non sarai in grado di eliminarli senza interrompere la compatibilità.


1
+1 per "semplificare l'aggiunta di una funzione piuttosto che rimuoverla".
R ..

3
una volta che non autorizzi i commenti nidificati, non puoi permetterli anche perché interromperanno tali commenti:/*/**/
RiaD

2

Una probabile ragione è che il parser deve gestire i commenti nidificati, poiché il sapore delle espressioni regolari comunemente utilizzate nei lexer non supporta la ricorsione. Quelli semplici possono essere eliminati come spazi bianchi dal lexer, quindi sono più semplici da implementare in quel modo.


3
Non è il "sapore". La parola "regolare" nell'espressione regolare esclude intrinsecamente la ricorsione.
R ..

3
@ R: In matematica, certo. Ma nella programmazione, abbiamo cose che chiamiamo regex che supportano la ricorsione.
Amara,

La domanda è: è forse un problema? Molte lingue hanno già a che fare con le parentesi di nidificazione. Per citarne alcuni: Lisp, C, Java, Python, Ruby, Perl.
Thomas Eding,

Le parentesi nidificate vanno bene, perché le cose all'interno delle parentesi sono le stesse delle cose esterne: token normali. Nei commenti, non hai token, hai solo testo. Devi essere in grado di abbinare i token dei commenti di inizio e fine in modo da sapere se 'int' è un tipo o solo una parola in un commento. (Soprattutto se si eliminano i commenti nel lexer.)
Alan Shutko il

2
@ThePopMachine: Sono sicuro di ciò che ho affermato, che il regolare ha un significato formale definito, non il significato che stai usando, e che il "regolare" in "espressione regolare" è stato scelto per questo significato. Essere non ricorsivi è un risultato della sua definizione.
R ..

-1

Chissà? Immagino perché supportare i commenti nidificati è più lavoro - dovresti mantenere una pila di qualche tipo e perché complica la grammatica della lingua.


-1

I commenti nidificati significano lavoro extra per il parser. Di solito quando vedi l'inizio di un commento, ignori tutto fino all'indicatore di commento finale. Per supportare i commenti nidificati è necessario analizzare anche il testo nei commenti. Il problema più grande, tuttavia, è che un programmatore deve fare attenzione a chiudere correttamente tutti i commenti nidificati o porterà a errori di compilazione. L'implementazione corretta di un compilatore è qualcosa che può essere fatto, ma tenere traccia dei commenti annidati come programmatore è piuttosto soggetto a errori e irritante.


3
-1: non vero. I parser sani non funzionano così.
Amara,
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.