2010-05-30 13 views
6

Sto facendo un semplice compilatore per un semplice linguaggio pet che sto creando e che proviene da uno sfondo C (anche se lo sto scrivendo in Ruby) mi chiedevo se fosse necessario un preprocessore.I preprocessi sono obsoleti nelle lingue moderne?

Cosa ne pensi? È ancora necessario un preprocessore "stupido" nelle lingue moderne? Le funzionalità di compilazione condizionale di C# potrebbero essere considerate un "preprocessore"? Ogni linguaggio moderno che non include un preprocessore ha le utilità necessarie per sostituirlo correttamente? (ad esempio, il preprocessore C++ è ora per lo più obsoleto (anche se ancora dipende) a causa dei modelli.)

+1

avrei _not_ dire che il preprocessore è obsoleta in C++. Molte cose per cui è stato usato in C possono essere fatte usando i template, ma ci sono ancora moltissimi usi per questo. –

+3

Il C++ ha ancora bisogno del preprocessore per i file '# include' - anche se spero che possiamo essere d'accordo sul fatto che ci sono modi più sicuri per gestire più file rispetto all'utilizzo di un preprocessore. – sepp2k

+0

@sepp @James sì questo è ciò di cui sto parlando. Chiunque faccia '#define foo (x) ...' in C++ non conosce i modelli C++ o sta lavorando su un codice legacy. – Earlz

risposta

8

La preelaborazione di C può fare cose davvero buone, ma se si guardano le cose che sono usate per te, capisci che spesso si tratta solo di aggiungere un altro livello di astrazione.

  • Pre-elaborazione per diverse operazioni su piattaforme diverse? È fondamentalmente uno strato di astrazione per l'indipendenza dalla piattaforma.
  • Pre-elaborazione per aggiungere facilmente codice complesso? Astrazione perché la lingua non è abbastanza generica.
  • Pre-elaborazione per l'aggiunta di estensioni nel codice? Astrazione perché il tuo codice/la tua lingua non è abbastanza flessibile.

Quindi la mia risposta è: non hai bisogno di un preprocessore se la lingua è abbastanza di alto livello *. Non chiamerei il pre-trattamento malvagio o inutile, dico solo che più la lingua diventa astratta, meno la ragione per cui posso pensare per aver bisogno di una pre-elaborazione.

* Che cosa è abbastanza alto? Questo è, ovviamente, del tutto soggettivo.

EDIT: Certo, mi sto veramente solo riferendosi al macro. L'uso dei preprocessori per l'interfaccia con altri file di codice o per la definizione di costanti è malvagia.

+0

+1 per * È fondamentalmente uno strato di astrazione per l'indipendenza dalla piattaforma. * I macro –

+0

sono malvagi solo se non li indefiniamo. Gli sviluppatori di C dovrebbero essere costretti a usare solo macro in ambiti specifici e indefiniti quando hanno finito di usarli. ad es. #define options, #include header, l'header fa un lavoro e deseleziona le opzioni e lascia la struttura grezza dietro, o se è un'intestazione di utilità, lo si #include, poi si annulla #INSTALL e #include nuovamente l'intestazione e dovrebbe pulire tutti i suoi macro. In caso contrario, l'ambito globale diventa abbastanza veloce, vedere API di Windows per vederlo al limite. – Dmitry

7

Il preprocessore è un metodo economico per fornire strutture di metaprogrammazione incomplete a una lingua in un modo brutto.

Preferiscono invece le macro metaprogrammazione o in stile Lisp.

+0

Ben detto. Chiunque progetta una lingua oggi senza macro o qualcosa di equivalente dovrebbe avere la licenza di progettazione linguistica portata via. Vedi Converge (http://ConvergePL.Org/) per come fare un potente sistema di metaprogrammazione in fase di compilazione in un linguaggio non omoiconico con molta sintassi. –

2

Penso che i preprocessori siano una stampella per mantenere una lingua con scarso potere espressivo.

Ho visto così tanti abusi dei preprocessori che li odio con passione.

0

Un preprocessore è una fase separata della compilazione. Mentre la pre-elaborazione può essere utile in alcuni casi, il mal di testa e i bug che può causare lo rendono un problema.

In C, preprocessore viene utilizzato principalmente per:

  1. Compreso dati - Mentre potenti, i più comuni casi d'uso non hanno bisogno di un tale potere, e "importazione"/"utilizzando" roba (come in Java/C#) è molto più pulito da usare e poche persone hanno bisogno dei casi rimanenti;
  2. Definizione di costanti - Perché non fornire solo una dichiarazione "const"
  3. Macro: mentre le macro in stile C sono molto potenti (possono includere dichiarazioni come i ritorni), danneggiano anche la leggibilità.Generics/Templates sono più puliti e, sebbene meno potenti in alcuni modi, sono più facili da capire.
  4. Compilazione condizionale - Questo è probabilmente il caso d'uso più legittimo per i preprocessori, ma ancora una volta è doloroso per la leggibilità. Separare il codice specifico della piattaforma nel codice sorgente specifico della piattaforma e utilizzare le dichiarazioni comuni if ​​finisce per essere migliore per la leggibilità.

Quindi la mia risposta è mentre potente, il preprocessore danneggia leggibilità e/o non è il modo migliore per affrontare alcuni problemi. Le lingue più recenti tendono a considerare la manutenzione del codice molto importante e per queste ragioni il preprocessore sembra essere obsoleto.

+0

Penso che tu stia rendendo il problema più grande di quello che è. Sì, ottenere le transizioni di fase a destra è un problema difficile. Ma è un problema * risolto * difficile: la comunità Scheme lo ha capito decenni fa. Hai solo bisogno di rubare il loro lavoro. –

+0

In Scheme, non sembra essere un preprocessore. Significa che se esiste, sembra che sia stato fatto bene. – luiscubal

+0

Perché la compilazione condizionale dovrebbe essere il caso d'uso più legittimo per un preprocessore? Delphi gestisce la compilazione condizionale perfettamente senza un preprocessore ... –

0

È la tua lingua in modo che tu possa costruire qualsiasi funzionalità tu voglia nella lingua stessa, senza bisogno di un preprocessore. Non penso che un preprocessore dovrebbe essere necessario e aggiunge uno strato di complessità e oscurità in cima a una lingua. La maggior parte dei linguaggi moderni non ha preprocessori, e in C++ la usi solo quando non hai altra scelta.

A proposito, credo che D gestisca la compilazione condizionale senza un preprocessore.

+1

per qualche ragione, D sembra un'estensione C++ immaginaria che ha un compilatore vero e proprio –

+2

D ha 'static if' che è un'istruzione' if' che ottiene valutato al momento della compilazione invece del runtime. –

0

Dipende esattamente da quali altre funzionalità offrite. Ad esempio, se ho un const int N, offri per me l'assunzione di N variabili? Sono necessarie variabili membro N, prendere un argomento per costruirle tutte? Creare N funzioni? Eseguire N operazioni che non necessariamente funzionano nei cicli (ad esempio, passare argomenti N)? N argomenti del modello? Compilazione condizionale? Costanti che non sono integrali?

Il preprocessore C è così assurdamente potente nelle mani giuste, avresti bisogno di fare un linguaggio seriamente potente per non garantirlo.

5

Un preprocessore è non necessario. Per la metaprogrammazione reale, dovresti avere qualcosa come MetaML o Template Haskell o macro igienica. Schema. Per cose veloci e sporche, se gli utenti devono assolutamente averlo, c'è sempre m4.

Tuttavia, un linguaggio moderno dovrebbe supportare l'equivalente delle direttive C #line. Tali direttive consentono al compilatore di individuare errori nella fonte originale, anche quando tale origine è incorporata in un generatore di parser o un generatore di lexer o un programma di scrittura. In altre parole,

  • Progetta la tua lingua in modo da non aver bisogno di un preprocessore.
  • Non associare la tua lingua con un benedetto preprocessore.
  • Ma se gli altri hanno le proprie ragioni per l'utilizzo di un preprocessore (la generazione di parser è popolare), fornire supporto per i messaggi di errore precisi.
0

Direi che, sebbene si debba evitare il pre-processore per quasi tutto ciò che si fa normalmente, è ancora necessario.

Ad esempio, in C++, per scrivere una libreria di test delle unità come Catch, è assolutamente necessario un pre-processore. Lo usano in due modi diversi: uno per l'espansione dell'asserzione e uno per le sezioni di nidificazione nei casi di test .

Tuttavia, il pre-processore non deve essere utilizzato in modo improprio per eseguire calcoli in compilazione in C++ in cui è possibile utilizzare le espressioni costali e la meta-programmazione modello.


Mi dispiace, non abbiamo abbastanza reputazione di inviare più di due link, quindi sto mettendo questo qui:

  1. github.com/philsquared/Catch/blob/master/ docs/assertions.md
  2. github.com/philsquared/Catch/blob/master/docs/test-cases-and-sections.md
Problemi correlati