2014-12-09 21 views
6

Ho lavorato con il linguaggio Scala per alcuni mesi e ho già creato un paio di progetti in Scala. Ho trovato che Scala REPL (almeno la sua implementazione del foglio di lavoro IntelliJ) è abbastanza comoda per lo sviluppo rapido. Posso scrivere codice, vedere cosa fa ed è bello. Ma faccio la procedura solo per le funzioni (non per l'intero programma). Non posso avviare la mia applicazione e cambiarla in loco. O almeno non so come (quindi se lo sai, puoi darmi un consiglio).Qual è la differenza tra Clojure REPL e Scala REPL?

Alcuni giorni fa il mio socio mi ha parlato di REPL Clojure. Usa Emacs per il processo di sviluppo e può cambiare codice in loco e vedere i risultati senza riavviare. Ad esempio, avvia il processo e se modifica l'implementazione di una funzione, il suo codice cambierà il suo comportamento senza riavviare. Mi piacerebbe avere la stessa cosa con il linguaggio di Scala.

P.S. Non voglio discutere né quale sia la lingua migliore né la programmazione funzionale migliore di quella orientata agli oggetti. Voglio trovare una buona soluzione. Se Clojure è la lingua migliore per l'attività, lascia che sia.

+2

Uno è usato per scrivere Clojure, l'altro per scrivere Scala. Inoltre: http://stackoverflow.com/questions/2471947/is-there-an-easy-way-to-get-the-scala-repl-to-reload-a-class-or-package – vptheron

+0

È un po 'difficile per me sapere quale sarebbe la risposta corretta? Stai forse chiedendo se il REPL di Scala può ridefinire le funzioni in un programma in esecuzione? –

+0

Curiosità, la domanda è buona, ma il titolo non lo è. – Mars

risposta

18

La risposta breve è che Clojure è stato progettato per utilizzare un compilatore a passaggio singolo molto semplice che legge e compila una singola espressione o forma alla volta. Nel bene e nel male non ci sono informazioni di tipo globale, nessuna inferenza di tipo globale e nessuna analisi o ottimizzazione globale. Clojure utilizza le istanze clojure.lang.Var per creare associazioni globali mediante una serie di hashmap dai simboli testuali ai valori transazionali. I moduli def creano tutti i collegamenti nell'ambito globale in questa mappa di associazione globale. Quindi, se in Scala una "funzione" (metodo) verrà risolta in un'istanza o in un metodo statico su una determinata classe JVM, in Clojure una "funzione" (def) è in realtà solo un riferimento a una voce nella tabella delle associazioni var. Quando viene invocata una funzione, non esiste un collegamento statico ad un'altra classe, invece la var è di riferimento con un nome simbolico, quindi viene dereferenziata per ottenere un'istanza di un oggetto clojure.lang.IFn che viene quindi richiamato.

Questo livello di riferimento indiretto significa che è possibile rivalutare solo una singola definizione alla volta e che la rivalutazione diventa globale visibile a tutti i client della variabile ridefinita.

In confronto, quando una definizione in Scala cambia, scalac deve ricaricare il file modificato, macroexpand, digitare infer, tipo check e compilare. Quindi, a causa della semantica del caricamento di classi sulla JVM, scalac deve anche ricaricare tutte le classi che dipendono dai metodi della classe che sono cambiati. Anche tutti i valori che sono istanze della classe modificata diventano trash.

Entrambi gli approcci hanno i loro punti di forza e di debolezza. Ovviamente l'approccio di Clojure è più semplice da implementare, tuttavia paga un costo costante in termini di prestazioni a causa delle continue operazioni di ricerca delle funzioni che dimenticano i problemi di correttezza dovuti alla mancanza di tipi statici e di cosa hai. Ciò è probabilmente adatto a contesti in cui molti cambiamenti avvengono in un breve lasso di tempo (sviluppo interattivo) ma è meno adatto al contesto quando il codice è per lo più statico (distribuzione, quindi Oxcart). some work I did suggerisce che il rallentamento dei programmi Clojure dalla mancanza di collegamento del metodo statico è dell'ordine del 16-25%. Questo non è per chiamare Clojure slow o Scala veloce, hanno solo priorità diverse.

Scala sceglie di fare più lavoro in anticipo in modo che l'applicazione compilata funzioni meglio, che è probabilmente più adatta per l'implementazione dell'applicazione quando si verificherà un ricaricamento minimo o nullo, ma si rivela un trascinamento quando si vogliono apportare molte piccole modifiche .

Alcuni materiali che ho a disposizione sulla compilazione del codice Clojure più o meno cronologico per ordine di pubblicazione da quando Nicholas ha influenzato molto il mio lavoro GSoC.

che suppongo mi lascia in il luogo infelice di dire semplicemente "Mi dispiace, Scala non è stato progettato per questo nel modo in cui C lojure era "per quanto riguarda lo scambio di codice a caldo.

+1

Gilad Bracha e altri luminari dei mondi Smalltalk e Lisp hanno questo mantra che "Tipi statici sono accoppiati", e questo è un altro esempio di questo. È - almeno al meglio delle nostre attuali conoscenze - semplicemente non è possibile implementare un ambiente vivace per un linguaggio tipizzato staticamente, mentre le lingue tipizzate dinamicamente hanno * ambienti estremamente potenti e vivaci, controlla la MIT Lisp Machine, Squeak/Pharo Smalltalk , Newspeak, Lively Kernel di Dan Ingall o Self World. –

+0

Grazie mille a tutti! – Curiosity

+0

@ JörgWMittag È sempre un compromesso tra l'essere dinamici e il dover essere controllati staticamente. A volte ne vuoi uno, a volte vuoi l'altro. Tendo ad appoggiare il lato tipizzazione statico, soprattutto perché ho visto alcuni bug che si verificano anche in Java perché il suo sistema di tipi è troppo indulgente. Non si tratta di eliminare i vantaggi della digitazione dinamica, per me i vantaggi della digitazione statica pesano semplicemente di più. YMMV – Cubic