È eval il defmacro di javascript?

2

In Common Lisp, defmacro ci consente fondamentalmente di creare la nostra DSL.

Ho letto questa pagina oggi e spiega qualcosa di intelligente fatto:

But I wasn't about to write out all these boring predicates myself, so I defined a function that, given a list of words, builds up the text for such a predicate automatically, and then evals it to produce a function.

Che mi sembra appena defmacro .

eval è defmacro di javascript? Potrebbe essere usato come tale?

    
posta Florian Margaine 05.10.2012 - 14:58
fonte

2 risposte

11

Può, ma è più pericoloso.

defmacro ha tre caratteristiche principali:

  1. Viene eseguito in fase di compilazione;
  2. È una vera sostituzione sul posto; e
  3. A causa dell'intera natura della sintassi Lisp, funziona a un livello AST, non a un livello di codice sorgente.

Al contrario, eval :

  1. Esegue in fase di esecuzione;
  2. Non è una sostituzione sul posto; e
  3. Funziona con le stringhe.

Perché è importante?

Per prima cosa, eval ha una penalità di velocità: poiché deve valutare i suoi argomenti ogni volta che viene chiamata, invece di una sola volta in fase di compilazione, avrai un hit di velocità ad ogni esecuzione del programma.

In secondo luogo, non esiste una convalida in fase di compilazione in cui il eval passi effettivamente qualcosa di sano. Puoi avere un errore di sintassi orribile nel tuo argomento eval (o, peggio, un orribile errore di sintassi solo quando chiamato in determinati modi ), ma non verrà catturato fino a quando il tempo di esecuzione non sarà lungo la strada . Poiché le macro Lisp sono in fase di compilazione, non è possibile averlo. La tua macro potrebbe non funzionare, sia chiaro, ma verrà compilata per definizione a qualcosa di valido.

Terzo, eval ha seri problemi di sicurezza rispetto a defmacro . Poiché le macro Lisp funzionano con l'AST, c'è un alto livello di sicurezza. Indipendentemente dall'argomento che fornisci la macro in fase di runtime, tali argomenti non possono consentire a un chiamante malintenzionato di "uscire" dalla macro o di chiamare codice dannoso. Non è vero per eval : se non pensi che la tua stringa sfugge molto, molto attentamente e consenti a qualsiasi forma di input generato dall'utente nella stringa eval , rischi di consentire l'esecuzione di codice dannoso.

Ok, ma, qualunque sia, posso sentirti dire. L'utente dovrebbe farlo da solo, ed è già il suo browser, quindi perché preoccuparsi?

Perché ci sono molti modi per iniettare script in quella situazione. Richieste di script tra siti, ad esempio, o dimenticanza di eseguire correttamente una stringa che si archivia in un database. Ci sono lotti di modi per introdurre valori dannosi in quelle macro e, nel momento in cui ciò accade, i dati dei tuoi utenti sono tostati.

Infine, anche se tutto ciò non ti dissuade, il eval di JavaScript in particolare è semplicemente meno potente. Ci sono strani modi in cui interagisce con l'ambito variabile incluso e l'ambito della variabile globale, ad esempio, e non esiste un modo corretto per fare l'equivalente del gensym del Common Lisp per l'igiene delle variabili.

Puoi utilizzare eval in alcuni dei luoghi che potresti utilizzare defmacro ? Sicuro. Ma sono difficilmente intercambiabili, e spero che la spiegazione di cui sopra chiarisca il motivo per cui assolutamente zero i buoni framework JavaScript che conosco usano eval .

Invece, se davvero ti trovi in cerca di macro, vai a trovare un linguaggio compilato su JavaScript che le abbia, come ClojureScript. In questo modo otterrai i vantaggi delle macro Lisp senza gli svantaggi di eval .

    
risposta data 05.10.2012 - 15:52
fonte
3

Siccome eval può eseguire javascript arbitrario sono sicuro che potresti mettere insieme qualcosa simile a un sistema macro. Detto questo, javascript non è homoiconic allo stesso modo di Common Lisp o Scheme. Homoiconicity (?) È il termine di fantasia per il vecchio mantra di lista di "Codice come dati". Un sistema macro trasforma il codice. Questo è molto naturale quando puoi manipolare il codice nello stesso modo in cui manipoli altri dati perché tutto è un elenco (LISt Proccessing). Possiamo elencare molti modi in cui javascript "è una lisc", ma non tratta il codice come dati.

In un sistema macro lisp, manipoliamo le liste. In un "sistema macro javascript" (nota le virgolette) dobbiamo manipolare le stringhe o qualche AST complicato.

C'è un famoso antecedente su cui qualcuno sta facendo un discorso su tutti i modi in cui Python è un lisp "funzioni di prima classe bla bla bla". Alla fine, John McCarthy (inventore di Lisp) alza la mano e chiede "Tratta il codice come dati?" Zing .

In conclusione, eval potrebbe probabilmente essere usato per virare un sistema macro su javascript. Ma non sarebbe così naturale come defmacro di Common Lisp.

    
risposta data 05.10.2012 - 15:54
fonte

Leggi altre domande sui tag