Programmazione automatica: scrivere codice che scrive codice [chiuso]


105

Dopo aver letto il libro The Pragmatic Programmer , uno degli argomenti che ho trovato più interessante è stato "scrivere codice che scrive codice".

Ho provato a cercare in rete altre spiegazioni o articoli a riguardo, e mentre ho trovato alcuni buoni articoli sull'argomento, non ho ancora trovato alcuna implementazione specifica del codice o buoni esempi.

Sento che non è ancora un argomento così comune, qualcosa che manca di documentazione o non è abbracciato da così tante persone, e vorrei saperne di più.

Cosa ne pensi dell'argomento? È qualcosa che aumenterà davvero la tua produttività? Quali sono alcune buone risorse in materia, tra libri, blog, presentazioni, ecc?


Alcuni esempi di codice sarebbero molto apprezzati per permettermi di comprenderne meglio l'implementazione.


Ecco la pagina wiki sull'argomento con varie tecniche di programmazione pertinenti, come Meta Programming, Generative Programming e Code Generation.


32
Una volta ho scritto codice che ha scritto codice che ha scritto codice ... :)
Benjol,

9
@Benjol: scrivevi in ​​Lisp?
compman,

11
Inoltre, le lingue lato server lo fanno continuamente generando HTML, CSS e JavaScript. Potresti avere uno script sul lato server che crea uno script sul lato server che crea html con javascript che crea più html e nessuno se ne interesserà a causa di quanto sia comune .
zzzzBov,

8
Se non lo hai già fatto, dai un'occhiata a questa serie di articoli di IBM developerWorks: " L'arte della metaprogrammazione " Parte 1 , Parte 2 e Parte 3 .
John Tobler,

3
AtomWeaver ( atomweaver.com ) è un buon esempio di programmazione automatica: in primo luogo, crei mini-programmi riutilizzabili in Lua. Quindi, modellare il sistema riutilizzando queste risorse. AtomWeaver quindi tesse un programma Lua che contiene i "mini-generatori" per generare il codice sorgente finale del sistema. È quindi possibile modificare il modello e rigenerarlo.
Rui Curado,

Risposte:


49

Nel mondo Lisp, è abbastanza comune vedere il codice che scrive il codice che scrive il codice (e così via). Quindi, qualsiasi progetto Lisp o Scheme di dimensioni decenti servirà come un buon esempio di codice. Consiglio di guardare al compilatore di Racket e alle fonti di runtime, così come a Bigloo , le loro librerie sono semplicemente geniali.

Per quanto riguarda la produttività: sto usando la metaprogrammazione come tecnica dominante in quasi tutto il mio lavoro di sviluppo, e chiaramente aiuta molto, sia riducendo le dimensioni del codice sia aumentandone la leggibilità. La chiave sta nell'uso di linguaggi specifici di dominio e la metaprogrammazione è uno dei modi più efficienti per implementarli.


67

Preferisco andare un po 'oltre e, invece di scrivere codice che scrive codice, scrivere codice che genera oggetti, metodi, funzioni. Ciò può essere ottenuto ad esempio con macro Lisp o funzionalità di modifica dinamica del programma Ruby.

La piccola differenza è che non finisci con i file sorgente che sono stati generati automaticamente. Di solito questi file non sono leggibili dall'uomo e non possono essere modificati, quindi perché preoccuparsene. Non mi piace l'idea di aumentare la mia base di codice con qualcosa che non posso controllare.

Un libro che mi è piaciuto leggere sull'argomento era Metaprogramming Ruby (se conosci il linguaggio Ruby)


Modifica dopo la seguente domanda nel commento:

Perché dovrebbe essere utile devo ancora codificare il codice di generazione? Devo scrivere un codice in grado di generare cose diverse a seconda dell'input dell'utente, in modo da poterlo riutilizzare più volte?

Innanzitutto, la metaprogrammazione non è un obiettivo, ma uno strumento. Non usare la metaprogrammazione perché "è bello" o "X ha detto che ogni sviluppatore dovrebbe usarlo".

Penso che un buon motivo per usare la metaprogrammazione sia generalizzare alcuni schemi comuni (schema come qualcosa che si ripete) che hai trovato nel tuo codice e che nessun'altra tecnica di programmazione usuale (eredità, schemi di progettazione, ecc.) Può raggiungere.

Come affermato dalla Giordania , un caso d'uso tipico è la gestione del database e ORM (Object Relation Mapping). Ancora una volta, in Ruby, dovresti guardare ActiveRecord che è un ottimo esempio di metaprogrammazione applicata a ORM.

Come nota finale:

Non pensare "Voglio applicare la metaprogrammazione, dove posso applicarla nel mio codice?".

Pensa "Vedo questo schema che si ripete in tutto il mio codice, non riesco a trovare un modo per trasformare il codice in qualcosa di più piccolo e riutilizzabile. Forse la metaprogrammazione può aiutarmi?"


3
@Jose: più comunemente generi codice tramite template. C'è ad esempio la velocità di apache (N-) o i modelli T4 di Visual Studio. Quindi hai solo un programma che alimenta i metadati nei tuoi modelli e crea nuovi file da allora. È abbastanza facile e lo faccio continuamente per generare scheletri dell'interfaccia utente, entità ecc.
Falcon,

2
@Jose Faeti, dai un'occhiata più da vicino alle macro Lisp (o Clojure o Nemerle, a seconda delle tue preferenze sulla piattaforma).
SK-logic,

1
Vorrei aggiungere la metaprogrammazione in grado di sostituire alcuni modelli come la politica o lo stato, ma senza costi di runtime. Questo non è solo per problemi che non possono essere raggiunti con il refactoring comune, ma a volte anche un'alternativa migliore.
deadalnix,

1
@Jose Faeti: Vedo che conosci un po 'di Python. Ha anche capacità di metaprogrammazione, anche se non le ho usate davvero. Dai un'occhiata a Dangerously Advanced Python PDF
Kit

3
@Falcon: IMO è il modo peggiore per generare codice; è molto difficile aggirare le lingue senza alcuna funzione di meta-programmazione integrata. Invece di generare Java o C #, sarebbe meglio scrivere quel codice in un linguaggio JVM o .NET di livello superiore.
Kevin Cline,

19

Ancora meglio, usa il codice che qualcun altro ha scritto che scrive il tuo codice per te.

L'automazione del codice è generalmente buona per gli ORM e altri codici di interazione del database e, naturalmente, per la creazione di codici ripetitivi ma simili.

Ovviamente, se stai costruendo un sacco di lezioni simili, forse avresti potuto ottenere la stessa cosa in un linguaggio dinamico molto prima, ma sto divagando.

Questo è abbracciato da molte persone, anche se spesso troverai il software etichettato come generatori di codice.

Vedi aziende e prodotti come CodeSmith e MyGeneration, oppure dai un'occhiata a questo articolo di Wikipedia: http://en.wikipedia.org/wiki/Comparison_of_code_generation_tools


6
Non è meglio. Il tuo prezioso codice così piccolo non può essere gestito in modo adeguato da qualche altro strumento di generazione del codice di un tipo, in quanto quell'altro tipo non sa nulla delle tue specifiche. L'uso più produttivo della metaprogrammazione è l'implementazione di linguaggi specifici del dominio e, come suggerisce il nome, sono specifici per il tuo dominio molto problematico, non possono essere implementati da nessun altro tranne te.
SK-logic,

@ SK-logic: che dire del codice generato da ORM? È generato da un altro strumento / libreria e soddisfa ancora molte esigenze di progetto.
David,

@David, a dire il vero, non sono del tutto convinto con gli ORM generici. Ho avuto così tanti problemi con loro in passato, ricorrendo spesso all'implementazione dei miei piccoli ORM specifici.
SK-logic,

1
@Jordan, tutti quegli strumenti sono troppo specifici (e peggio ancora - basati sul testo , cioè inferiori rispetto al design). Sto invece parlando della corretta metaprogrammazione.
SK-logic,

1
@AtillaOzgur, possono essere "molto buoni", vero. Ma non sono migliori degli eDSL. La generazione di codice autonomo è ovviamente molto più limitata e molto meno flessibile della macro metaprogrammazione.
SK-logic,

16

Uno degli esempi classici è lex e yacc. Il loro scopo principale è quello di evitare la fatica di scrivere qualsiasi tipo di parser. Lungo la strada, rendono molto più veloce la costruzione di parser complessi con molte regole e stati, ed evitano anche tutti gli errori a sorpresa fatti dalle persone che fanno i propri.

Questa è anche l'idea alla base di c, che è uno strumento per scrivere assemblatore. La stessa cosa vale per qualsiasi lingua di alto livello che ti interessa nominare. Per gli strumenti che scrivono codice per te, ci sono alcuni semplici paradigmi.

Un IDE corretto aiuta fornendo documentazione a portata di mano, completamento automatico intelligente e frammenti di codice. Gli IDE includono anche vari modelli, quindi non è necessario avviare un programma da zero. Esistono programmi per prendere un diagramma uml e svelare le lezioni in un linguaggio di alto livello.

Infine, puoi scrivere i tuoi strumenti per la generazione di codice all'interno del tuo set di problemi. Ecco come sono iniziate lex e yacc. Qualsiasi tipo di lingua specifica per il dominio esiste proprio per questo motivo. Si creano alcuni blocchi predefiniti che descrivono la soluzione in un codice più semplice da comprendere, concludendo attività comuni o sezioni complicate con semplici comandi. Non stai cercando una soluzione per ogni problema, solo una definizione più semplice di quella specifica con cui hai a che fare.

In un certo senso, tutto ciò che fai sopra il livello binario è l'automazione del codice.


È davvero una bella vista. Tutto sommato è solo un altro dei molti metodi che i programmatori cercano di utilizzare per facilitare le loro operazioni e concentrarsi su un livello superiore di codifica, anziché sui dettagli del codice di sintassi.
Jose Faeti,

1
@Jose Faeti L'articolo di wikipedia en.wikipedia.org/wiki/Automatic_programming contiene collegamenti a vari strumenti diversi, se sei interessato a maggiori dettagli. Suggerirei anche di leggere su lex e yacc, in quanto c'è un po 'più di documentazione e descrizione per quelli.
Spencer Rathbun,

In linguaggi sufficientemente potenti (ad es. C ++ rispetto a C), strumenti esterni come lex e yacc non sono necessari.
Kevin Cline il

YACC non scrive "nessun tipo di parser". Scrive un tipo specifico di parser (LALR) che è molto difficile da ottenere senza un aiuto automatico. Esiste un altro tipo di parser (discesa ricorsiva) che è molto più facile da scrivere e ottenere correttamente, e di conseguenza più facile da leggere e capire cosa sta succedendo.
Mason Wheeler,

@MasonWheeler Il tipo di parser si riferiva alle grammatiche che possono essere create per risolvere i problemi, in un senso ampio e non esatto. Leggendolo un anno dopo, non è così chiaro come mi sarebbe piaciuto. Non sono sicuro di essere d'accordo con te sul fatto che i parser LL (*) siano più facili da scrivere e usare, comunque.
Spencer Rathbun,

13

metaprogrammazione

La metaprogrammazione è una tecnica controversa in molti negozi. Il motivo è che, come qualsiasi strumento potente, l'entità dell'aiuto o del dolore è grande.

Professionisti

  • Più espressivo, meno codice da scrivere e mantenere (spesso di un ordine di grandezza o più)
  • Coerenza, comportamento più coerente rispetto alla classe di problemi risolti con il codice
  • Produttività, meno codice per una soluzione a uno spazio maggiore di problemi

Contro

  • Complessità, può essere molto complicato anche se c'è meno codice
  • La sicurezza, a volte la sicurezza del tipo e l'analisi statica in generale saranno sacrificate
  • I bug interessano di più, piccoli errori avranno un impatto maggiore

Sono un grande fan della metaprogrammazione, ma lo faccio da molto tempo. Per me il compromesso tra dimensioni ridotte del codice e comportamento coerente è più che compensare i rischi. Meno codice significa meno bug, meno codice da mantenere, e di solito posso aggiungere grandi funzionalità molto rapidamente.

Tuttavia, ciò non significa che penso che tutti i programmatori dovrebbero impegnarsi in esso. Ho visto e ho dovuto risolvere grossi problemi creati dalla metaprogrammazione. Di solito da quando le persone che non capiscono il concetto e hanno tentato di estendere la funzionalità o semplicemente correggere un bug. Ci vuole una mentalità particolare che sia almeno orientata ai dettagli. La domanda per utilizzare le tecniche di metaprogrammazione dovrebbe essere una decisione del team . Se hai membri del team che non capiscono, non hanno il temperamento per questo, o sono solo contro di esso, nessuno del team dovrebbe usare la metaprogrammazione.


Grazie per le utili considerazioni! Potresti suggerirmi un compito davvero semplice e di base che sarò in grado di implementare usando la metaprogrammazione, che mi farà risparmiare tempo rispetto alla normale codifica, un piccolo esempio di codice?
Jose Faeti,

ahah mi fa venire in mente un errore che ho avuto diversi anni fa con GCC. 162 righe per mettere il messaggio di errore sul mio schermo. Metaprogrammazione ricorsiva FTW!
deadalnix,

6
La complessità della metaprogrammazione è altamente sopravvalutata. Non c'è assolutamente nulla di complicato, purché tu stia usando gli strumenti giusti. E i DSL sono molto più facili da eseguire il debug e la manutenzione rispetto al tipico codice boilerplate. Inoltre, non riesco a capire perché si debba sacrificare la sicurezza dei tipi: è esattamente il contrario, i DSL possono avere anche sistemi di tipo specifici per il dominio, altamente efficienti.
SK-logic,

2
@ SK-logic: non tutte le lingue supportano bene la metaprogrammazione. Quindi a volte vengono sacrificate cose come la sicurezza dei tipi (es. C) . Anche la metaprogrammazione non è solo DSL. Include cose come la programmazione dello stile di spedizione, generici, curry, ispezione di oggetti, applicazioni dinamiche, ecc. Per quanto riguarda la complessità, penso che sia facile per noi (persone con esperienza di metaprogrammazione) dire che non è complicato. Ho visto altre difficoltà a comprendere tutti i casi in cui il codice verrà eseguito. Dipende principalmente dalla loro esperienza e dalla tecnica coinvolta.
dietbuddha,

@dietbuddha, potresti per favore elaborare, perché si dovrebbe sacrificare la sicurezza del proprio DSL proprio, non importa come sia implementato? Puoi scrivere un interprete ad hoc in una C pura con un sistema di tipo forte (vedi Ad esempio gli abbracci). È possibile scrivere un generatore di codice indirizzato a C che esegue tutto il controllo ortografico stesso, senza fare affidamento sul sistema di tipi di lingua di destinazione. Per complessità: la maggior parte delle persone lo sta facendo in modo inutilmente complesso, mentre tutte le stesse metodologie di progettazione possono essere applicate alla generazione del codice come nella programmazione "normale". Quasi nessuna nuova conoscenza è richiesta.
SK-logic,

9

La maggior parte del codice scrive il codice. Ad esempio il codice php aiuta a scrivere HTML. La libreria php pdo aiuta a scrivere chiamate SQL. Le funzioni I / O del file scrivono il codice per comunicare con il sistema operativo. Anche una normale chiamata di funzione è un riferimento a un altro blocco di codice che viene eseguito. Quindi le chiamate delle tue funzioni scrivono codice.

In termini generali, possiamo pensare al calcolo come a codici di scrittura che scrivono codici in modo ricorsivo formando uno stack che termina quando si scontra con la realtà fisica dei codici collegati all'hardware.


3
Non chiamerei HTML un linguaggio di programmazione. È una sintassi per i documenti
Simon Bergot,

3
@Simon è un punto interessante. Esistono tutte le varietà di poteri espressivi per i diversi codici che utilizziamo. Il codice può scrivere in una lingua più debole, in una lingua più forte o nella propria lingua.
Ben Haley,

5

Il modo in cui lo fai varia in base ai tuoi requisiti. Supponendo che tu stia utilizzando la generazione di codice statico, potresti scrivere tu stesso tutta l'infrastruttura o utilizzare un generatore esistente come CodeSmith o MyGeneration. Usando questi è sufficiente scrivere i modelli richiesti.

Il mio ultimo progetto che ha coinvolto questo è stato alcune schermate CR. ASP.NET di base (la generazione del codice è buona per questo). Il processo è andato a definire entità come metadati nei file xml. Scrivi modelli per coprire i vari artefatti richiesti (classi di entità, repository, classi di servizio, controlli asp.net, pagine asp.net ecc.). Eseguire il processo di generazione e modellare l'output.

C'è un certo sovraccarico nello scrivere i modelli ma possono essere riutilizzati per progetti simili successivi. Allo stesso modo le modifiche ai dati sottostanti vengono gestite modificando i metadati e rieseguendo la generazione rendendo le modifiche più semplici e veloci da implementare.

Per quanto riguarda i test. Poiché si tratta di un sistema basato su modelli, sarà necessario dedicare un po 'di tempo alla convalida iniziale dell'output del processo, se il modello è errato, tutti gli output da quel modello saranno allo stesso modo errati. Una volta che sei soddisfatto, puoi anche utilizzare i generatori di codice per creare test di base dai metadati xml che puoi estendere per coprire casi speciali. Tuttavia, ricorda che potresti ancora dover eseguire test del codice per soddisfare cose specifiche, la generazione del codice riduce il tuo lavoro, non lo elimina del tutto.


5

Nella nostra azienda utilizziamo alcuni strumenti che generano effettivamente classi C ++ o C # con dati scaricati da Internet. Queste classi sono contenitori di dati e contengono un gran numero di oggetti negli elenchi.


Qualcosa come i frammenti di codice trovati in alcuni IDE come Visual Studio per esempio?
Jose Faeti,

@Jose Il nostro strumento è solo un'applicazione per convertire l'output HTML in una classe. Quindi invece di scaricare i dati ogni volta che si avvia l'applicazione, li scarichiamo una volta e ne ricaviamo una classe.
Holli,

5

La metaprogrammazione fa parte della programmazione da molto tempo. Considera non solo strumenti come SWIG, o designer WYSIWYG, che creano codice, ma anche strumenti in linguaggio come il preprocessore di C, o anche i modelli di C ++ e i generici di C # / Java, per non parlare di Reflection.

In effetti, si potrebbe sostenere che ogni compilatore è solo un altro metaprogramma: prendono il testo del programma e producono un codice macchina o macchina virtuale. E la vita senza compilatori? Owch.


Esatto, ma come è possibile implementarlo nel proprio linguaggio di programmazione per aumentare effettivamente la produttività? Questo è quello che mi manca.
Jose Faeti,

5

Ecco un esempio concreto del mio passato.

Stavo lavorando in un sito che aveva circa 50 MB di codice sorgente Delphi usando BDE per l'accesso ai dati. Volevano passare all'utilizzo di Direct Oracle Access per consentire un aggiornamento Oracle oltre la versione più alta supportata da BDE (8i se ricordo bene).

Quindi, invece di convincere un team di programmatori a lavorare su ogni modulo e modulo dati modificando manualmente ogni componente, ho scritto uno script PERL che: -

  1. Analizzato DFM (file di modulo) e identificato tutti gli oggetti TQuery, TTable, TStoredProcedure e TDatabase - memorizzando gli elementi in un elenco.

  2. Analizzato il PAS (codice) e identificato l'utilizzo degli oggetti - i TQueries stavano effettuando aggiornamenti o selezioni? Inoltre, ha identificato tutti gli oggetti creati nel codice anziché rilasciati in un modulo nell'IDE.

  3. Riscrivere DFM e PAS modificando i tipi di oggetto in modo appropriato (ad esempio TTable -> TOracleDataSet con la proprietà SQL impostata su "select * from" ecc.) E il metodo chiama. Inoltre, se del caso, sono state aggiunte ulteriori chiamate al metodo per chiudere, aprire e impostare i parametri.

In breve, 3 settimane di lavoro modificano lo script per lavorare su diverse applicazioni scritte da diversi team con stili di codifica diversi invece della stima originale di oltre 5 sviluppatori che lavorano per 6 mesi.

E la ragione per cui ho persino pensato di usare questo approccio è stata attraverso la lettura di The Pragmatic Programmer


Fantastico, mi occupo di Perl da un paio di giorni e ho già creato alcuni strumenti di produttività per generare aree di lavoro di base per lo sviluppo Web, con tutte le directory, i file, ecc. Digitando semplicemente "crea spazio di lavoro"! :)
Jose Faeti,

1
@Jose Questa è l'idea. Usa i linguaggi di scripting per automatizzare cose ripetitive. Può essere una tantum in cui si ottiene un aumento della produttività 8x o come nel tuo caso qualcosa che richiede tempo che dovrai fare ancora e ancora.
mcottle,

4

Chiedete esempi ....

Quando si lavora con SQL, non è necessario modificare direttamente il database, ma si suppone che eseguano script che apportano le modifiche desiderate, comprese le modifiche strutturali al database (aggiunta di tabelle, colonne, chiavi primarie, vincoli e così via) . Abbastanza frequentemente dovrai fare la stessa azione contro un sacco di tabelle o colonne contemporaneamente, e farle una per una sarebbe noioso, uno script breve che genera uno script più grande che fa quello che vuoi può essere un vero risparmia tempo.

Ad esempio, prima che il tipo di dati DATE fosse introdotto in MS SQl Server, l'unica scelta per una colonna data era DATETIME che ha una parte temporale - una parte temporale che rende un po 'più difficile la gestione dei dati. Al momento dell'aggiornamento a una versione con il tipo di dati Date, è possibile che si desideri aggiornare le colonne in cui l'ora è sempre 00:00. In un database con dozzine o addirittura centinaia di colonne DateTime questo richiederebbe molto tempo. Ma è facile scrivere uno script che interroga tutte le tabelle, controllando ogni colonna con un tipo di dati di DATETIME per vedere se l'ora è sempre diversa dalle 00:00 e in caso contrario creare un'istruzione ALTER per la tabella / colonna per cambiare il tipo di dati su DATE. Presto, codice che scrive codice.


3

Dai un'occhiata alle macro CL (Common Lips). Secondo me è esattamente quello che vuoi. Le labbra sono perfette nella metaprogrammazione.

Inoltre suggerisco Nemerle se si desidera avere i poteri .NET con un supporto perfetto per la metaprogrammazione (comprese le macro)

Ma se vuoi un vero motore di generazione del codice dai un'occhiata alla parsimonia di Apache


3

Sto solo lavorando su un tale strumento. Nel nostro caso particolare generiamo il codice VB.NET basato sul livello dati sulle firme delle funzioni nel database.

Iniziare a lavorare su e con la generazione del codice è inizialmente difficile poiché non si ha idea di come generare il codice, ma una volta che si dispone di un insieme stabilito di regole e il codice che deve essere generato può sempre essere generato in base a tali regole , lavorare con quel codice non è così difficile. Naturalmente, a seconda della complessità della generazione del codice e del numero di regole, l'attività può diventare più difficile. Ma in sostanza, la generazione del codice automatico viene utilizzata per attività di codifica ripetitive e non per codice avanzato che varia molto.

Il test dell'output è duplice. Per prima cosa devi assicurarti che il codice sia compilato, ed è facile. Quindi devi assicurarti che l'output faccia quello che intendevi fare in base ai parametri su cui è stato generato .. e la difficoltà di ciò varia in base alla complessità del codice che generi.

La mia sincera raccomandazione è che se hai voglia di scrivere codice in modo ripetitivo e puoi permetterti il ​​tempo .. Prova a pensare se ciò che stai facendo non può essere fatto dal codice generato. E in tal caso (se è un codice ripetitivo rispetto a quasi sempre) pensa quante volte dovrai estenderlo, modifica leggermente quel codice e anche quante volte devi scrivere quel tipo esatto di codice. Se la risposta a una di queste è "molte", allora dovresti seriamente considerare di creare un generatore per quel codice .

Spero che aiuti,
IPP


Grazie per la risposta! Come vengono effettivamente implementate le regole nel tuo esempio?
Jose Faeti,

1
Non posso dirti tutte le regole ma posso darti alcuni esempi. Analizziamo l'interfaccia esposta da un database Oracle e prendiamo in considerazione le firme delle funzioni nell'interfaccia Oracle. In base alla firma generiamo il nome della funzione del livello dati. sappiamo che otteniamo sempre dal db una tabella di dati oracle come risultato che analizziamo e salviamo in una matrice di tipo di oggetto speciale che usiamo per memorizzare i nostri dati. inoltre, in base ai parametri di input / output della firma della funzione db, aggiungiamo i parametri di input e output corrispondenti alle funzioni che generiamo e così via ..
Ioan Paul Pirau,

3

Ho un modulo PHP che genera una pagina web contenente codice JavaScript che genera HTML. Sono tre strati proprio lì. Il ragazzo era così difficile da leggere!

In una classe di programmazione, abbiamo dovuto scrivere un programma che prendesse una stringa di formula dall'utente e la analizzasse e visualizzasse il valore. Il risolutore più impressionante ha semplicemente preso l'input dell'utente, lo ha avvolto in main () {printf ("% d", ...);} ed ha eseguito uno script per compilare, collegare ed eseguirlo. Non ha scritto un parser! Oggi potresti farlo in un'istruzione SQL SELECT.

È uno strumento con cui dovresti giocare, quindi riporlo per qualche giorno futuro quando sarà utile.


In realtà è la stessa cosa che stavo cercando di implementare! :) Ma poi ho deciso di codificarlo con Perl offline e funziona alla grande. Ho un sacco di funzioni che sto pensando di aggiungere!
Jose Faeti,

Sto scrivendo codice con un massimo di 20 livelli di trasformazioni da lingua a lingua, senza alcun problema. Non è più complicato che avere una profondità di stack di chiamate di 20 livelli. Quindi non sono assolutamente d'accordo sul fatto che sia uno strumento per " archiviarlo per qualche giorno futuro quando sarà utile " - la generazione del codice è sempre utile.
SK-logic

3

Ho sviluppato soluzioni di meta-programmazione pulite con Prolog . Dove l'applicazione principale (diciamo in C ++) traduce una definizione astratta di un problema in un'applicazione Prolog in fase di esecuzione, che viene quindi delegata. Spesso scrivere funzionalità equivalenti in C ++ richiederebbe per sempre.

Penso che questo scenario sia un caso eccellente a favore dell'argomento code-writing-code .


3

Cosa ne pensi dell'argomento?

La metaprogrammazione è più comunemente associata a linguaggi non dinamici, poiché c'è un momento più difficile nel raggiungere determinati comportamenti (come l'implementazione di un ORM) senza molte linee di codice non produttive e non intelligenti.

Ma anche in linguaggi più dinamici come PHP, la generazione di codice può essere un vero salvavita e aumentare la produttività in grande quantità. Nei quadri moderni è molto comune disporre di impalcature che generano la maggior parte del modello, forma, test e azioni comuni per un determinato oggetto aziendale dichiarato. È uno dei motivi per cui framework come symfony o RoR hanno così tanto successo, quegli strumenti di generazione del codice rendono il codice coerente molto rapidamente e aumentano la produttività dei programmatori.

Nei siti web, la maggior parte delle interazioni ruota attorno a quattro azioni principali:

  • Crea un elemento
  • Recupera un set di elementi (con possibile filtro)
  • Aggiorna un elemento con nuovi attributi
  • Elimina un insieme di elementi

Almeno tutto ciò che ruota attorno a queste 4 azioni principali potrebbe e IMHO DOVREBBE essere realizzato utilizzando strumenti di generazione del codice per raggiungere la massima produttività.

Nella mia azienda, usiamo symfony, e il suo admin-generator è uno strumento eccezionale, che genera persino codice in fase di esecuzione (e lo memorizza nella cache), il che significa che non abbiamo nemmeno bisogno di usare alcun tipo di attività o strumento esterno per generare nuovo codice, dobbiamo solo pulire la nostra cache. Consiglio vivamente di utilizzare questo tipo di strumento per le operazioni CRUD.

Ma fare ciò che hanno fatto i fantastici collaboratori di symfony non è un compito facile. Ho implementato alcune attività di generazione del codice da solo e fare qualcosa di veramente coerente e con una vasta implementazione per coprire la maggior parte dei casi non è facile.

È qualcosa che aumenterà davvero la tua produttività?

Credo che la metaprogrammazione sia molto importante nei livelli di lavoro inferiori (framework, cache, compilatori, ecc.) Ma qualcosa che dobbiamo affrontare con estrema cautela se stiamo facendo cose a livello aziendale.

L'uso della generazione del codice è senza dubbio un importante incentivo per la produttività. Implementare i propri strumenti di generazione del codice, non tanto a meno che non si stia costruendo un framework da soli.

Quali sono alcune buone risorse in materia, tra libri, blog, presentazioni, ecc?

La migliore risorsa per comprendere la programmazione è sempre un codice sorgente valido e ben commentato. Direi che esaminare i generatori di amministratori di RubyOnRails e Symfony è una buona idea.


3

Mentre molte risposte qui si riferiscono a ciò che è comunemente noto come meta-programmazione, c'era in effetti un campo associato all'IA noto come programmazione automatica che riguardava la comprensione o la sintesi di programmi [1].

Qualsiasi compilatore (o meta-programma, generatore di codice, traduttore, sistema macro, ...) lavora con trasformazioni, generando un output da un input eseguendo il suo algoritmo fisso di trasformazione. Ma un compilatore o meta-programma tradizionale non fornisce una definizione, una descrizione o un esempio di ciò che è un elenco (ad es. [5, 3, 9] => [3,5,9]), creare un algoritmo di ordinamento. Tali problemi sono di interesse di questo campo della "programmazione automatica".

[1] - Relazione sullo stato di avanzamento dei sistemi di comprensione del programma ftp://db.stanford.edu/pub/cstr/reports/cs/.../CS-TR-74-444.pdfShare


2

La meta-programmazione può essere molto difficile da mantenere. All'inizio sembra elegante, ma quando inizi a imbatterti in casi angolari, gli errori vengono colti in ritardo (sul codice che è stato generato) e il tutto diventa un incubo da usare / debug.

Ho principalmente scritto codice Python e nella mia esperienza la meta-programmazione è sempre una cattiva scelta con questo linguaggio. Puoi sempre riformattare le cose per farlo con noiose funzionalità linguistiche normali. Il risultato è meno funky, ma più facile da convivere.


qualsiasi tipo di codice può essere molto difficile da mantenere. E può essere molto semplice se fatto nel modo giusto. In effetti, la metaprogrammazione può aumentare la manutenibilità in ordine di grandezza. La tua esperienza con Python è, probabilmente, irrilevante per la vera metaprogrammazione, dal momento che Python non è molto adatto a questo modo di pensare, con il suo goffo AST troppo profondo. Ma anche con Python, ho usato la libreria Tempita con alta efficienza e non ho mai avuto problemi di manutenibilità, anche con un team che non aveva quasi nessuna esperienza precedente con Python.
SK-logic,

Sono interessato al tuo punto su AST Python. Hai usato tempita a scopo di meta-programmazione?
Simon Bergot,

questo ( docs.python.org/library/ast.html ) è un AST abbastanza ad hoc, e il parser fornisce un albero non ottimizzato, troppo pieno, il che rende problematica un'analisi (specialmente con la mancanza di una corretta corrispondenza del pattern in Python). Anche generare un AST non è molto conveniente. Ho usato tempita per produrre sia il codice Python che il codice C (cioè, pura metaprogrammazione basata su testo), ha funzionato bene per quel compito specifico (generazione di codice boilerplate). Ho anche usato spesso Python per generare codice C da alcune descrizioni di alto livello XML.
SK-logic,

2

OP richiede risorse.

Potresti trovare interessante il nostro DMS Software Reengineering Toolkit . Si tratta di un puro strumento di metaprogrammazione, destinato a creare strumenti personalizzati di analisi e trasformazione del programma.

[Per seguire un commento alla domanda di OP, quando viene utilizzato per creare uno strumento di trasformazione specifico, DMS è una linea di prodotti che scrive codice, che scrive codice:]

DMS raggiunge questo obiettivo agnostico (ma non indipendente) rispetto alle lingue di programmazione target. DMS fornisce i servizi standard richiesti da una vasta gamma di attività di metaprogrammazione, così come un sistema operativo fornisce una vasta gamma di servizi per attività di programmazione standard. Questi servizi includono analisi approfondite, costruzione automatica di alberi di sintassi abstact, adattamento di modelli e riscrittura su alberi, librerie di tabelle di simboli che gestiscono facilmente langauges con regole di scoping sgradevoli come ereditarietà multipla, flusso di controllo, flusso di dati, punti e chiamata analisi del grafico. Niente di tutto ciò è significativo in assenza di linguaggi specifici da elaborare, quindi DMS accetta definizioni linguistiche legate a questi macchinari generali, producendo analisi specifiche della lingua, costruzione di AST, corrispondenza / riscrittura dei pattern specifici della lingua target usando il target- sintassi del linguaggio,

E come un sistema operativo, DMS è progettato per avere pochissime opinioni o vincoli su quali (meta) programmi si desidera scrivere, il che significa che può essere utilizzato per un'ampia varietà di scopi: estrarre metriche, trovare codice morto, implementare tessitori di aspetto, tradurre linguaggi, generazione di codici da DSL, ricerca di applicazioni di grandi dimensioni. (DMS è già stato utilizzato per tutte queste attività).

Uno ha bisogno di definizioni linguistiche solide se non vuoi passare il tempo a codificare tutto nel manuale di riferimento di lingua (pensa a cosa significa per Java e C ++). DMS risolve questo problema disponendo di una libreria di definizioni complete di lingua. L'analogo qui è un po 'come avere un database avaialbe per il tuo sistema operativo; non è necessario implementarne uno per continuare a scrivere l'applicazione incentrata sul database.


2

Vedi il set di problemi 4 di Philip Greenspun del corso MIT 6.916: Ingegneria del software di servizi Web innovativi ( http://philip.greenspun.com/teaching/psets/ps4/ps4.adp ).

Il suo obiettivo dice: "Insegnare agli studenti le virtù dei metadati. Più specificamente, imparano come rappresentare formalmente i requisiti di un servizio Web e quindi costruire un programma per computer per generare i programmi per computer che implementano quel servizio."

Questo è uno dei problemi che le potenziali reclute di ArsDigita ( http://en.wikipedia.org/wiki/ArsDigita ) erano necessarie per risolvere durante la prima bolla.

Il libro "SQL for Web Nerds" Riferimenti di Philip nel pset è stato spostato in ( http://philip.greenspun.com/sql/ ).


2

Intorno al 2001 ho iniziato a lavorare a un progetto che faceva ampio uso di oggetti business e oggetti dati. Stavo costruendo il sito Web di front-end, ma sono stato riattaccato agitando i pollici perché il livello aziendale e il livello di accesso ai dati non erano completamente sviluppati. Dopo un paio di settimane, ho iniziato a dare un'occhiata a cosa facessero quegli strati. In sostanza, stavano esponendo i dati restituiti dalle procedure memorizzate come raccolte di oggetti con proprietà corrispondenti ai campi nei dati, oppure stavano prendendo i parametri di input e li inviavano alle procedure memorizzate per essere salvate nelle tabelle del database. C'era molta serializzazione / deserializzazione in atto tra i due livelli, c'era Microsoft Transaction Server coinvolto, una libreria di tipi IDL / ODL ... ma tutto si adattava a un modello.

2 settimane dopo, ho trovato un generatore di codice che scaricava IDL / ODL e scaricava anche gli oggetti business e dati. Aveva impiegato il ragazzo a costruire il business e gli oggetti del livello dati per 2 anni per arrivare al punto di debug e test di questi oggetti. In 2 settimane, con la generazione del codice, abbiamo avuto lo stesso output, ma poiché tutto è stato generato è stato praticamente privo di bug.

Quel generatore di codice (strumento CASE di livello inferiore) mi ha seguito in molte diverse iterazioni, per circa 8-10 anni, perché il principio era così semplice: stai facendo qualcosa che deve essere fatto quando parli con i database, è carino molto codice ripetitivo, e una volta capito bene non dovrai più preoccupartene.

Quindi sì: usa un generatore di codice, in particolare quando la codifica è ripetitiva e si adatta a un modello ben definito.

Ho conosciuto persone che usano macro RegX per fare cose simili o che usano formule Excel per fare cose simili (lo faccio anche io).


2

Un esempio di metaprogrammazione

Ho una libreria di autorizzazioni di Ruby chiamata Authority . Consente agli sviluppatori di porre domande nella loro app con metodi come current_user.can_read?(@post)e @post.readable_by?(current_user). A queste domande viene data risposta da classi di autori centralizzati.

Questa è la parte cruciale: l' autorità non sa quali metodi definire fino a quando non vede la configurazione dell'utente . La configurazione dell'utente potrebbe contenere:

config.abilities =  {
  ...
  :read      => 'readable',
  :microwave => 'microwavable',  # user-defined
  ...
}

In tal caso, ci deve essere un metodo simile current_user.can_microwave?(@post).

La metaprogrammazione lo rende possibile: dopo aver letto la configurazione, so quali metodi definire :

Authority.verbs.each do |verb|
  class_eval <<-RUBY, __FILE__, __LINE__ + 1 # allows for a nice bracktrace
    def can_#{verb}?(resource)
      resource.#{Authority.abilities[verb]}_by?(self)
    end
  RUBY
end
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.