Krótka odpowiedź brzmi, że Clojure został zaprojektowany do korzystania z bardzo prostego kompilatora z pojedynczym przejściem, który odczytuje i kompiluje pojedyncze wyrażenie lub formularz na raz. Na lepsze lub na gorsze nie ma informacji o typie globalnym, globalnej inferencji typów ani globalnej analizy lub optymalizacji. Clojure wykorzystuje instancje clojure.lang.Var
do tworzenia globalnych powiązań za pośrednictwem serii hashmap od symboli tekstowych do wartości transakcyjnych. def
tworzy wszystkie tworzy powiązania w zasięgu globalnym w tej globalnej mapie wiążącej. Więc gdzie w Scali "funkcja" (metoda) zostanie rozwiązana do instancji lub metody statycznej na danej klasie JVM, w Clojure "funkcja" (def) jest tak naprawdę tylko odniesieniem do wpisu w tabeli powiązań var. Gdy funkcja jest wywoływana, nie ma statycznego łącza do innej klasy, zamiast tego var jest referencją pod nazwą symboliczną, a następnie dereferencji, aby uzyskać wystąpienie obiektu clojure.lang.IFn
, który jest następnie wywoływany.
Ta warstwa pośrednia oznacza, że możliwa jest ponowna ocena tylko jednej definicji na raz, a ponowna ocena staje się globalna widoczna dla wszystkich klientów ponownie zdefiniowanego pliku var.
Dla porównania, gdy definicja w Scali się zmienia, skalak musi ponownie załadować zmieniony plik, makrozwróć, wpisać zwrot, sprawdzić typ i skompilować. Następnie ze względu na semantykę ładowania klas w maszynie JVM, skalak musi również ponownie załadować wszystkie klasy, które zależą od metod w klasie, które uległy zmianie. Również wszystkie wartości będące instancjami zmienionej klasy stają się koszami.
Oba podejścia mają swoje mocne i słabe strony. Oczywiście podejście Clojure jest łatwiejsze do wdrożenia, jednak płaci się stały koszt pod względem wydajności ze względu na ciągłe operacje wyszukiwania funkcji zapomnieć o problemach z poprawnością ze względu na brak typów statycznych i co ty. Jest to prawdopodobnie odpowiednie dla kontekstów, w których wiele zmian dzieje się w krótkim czasie (rozwój interaktywny), ale jest mniej odpowiednie dla kontekstu, gdy kod jest w większości statyczny (wdrożenie, stąd Oxcart). some work I did sugeruje, że spowolnienie w programach Clojure z braku statycznego łączenia linek jest rzędu 16-25%. To nie nazywa się Clojure slow lub Scala szybko, mają tylko inne priorytety.
Scala postanawia wykonać więcej pracy z góry, aby skompilowana aplikacja działała lepiej, co jest prawdopodobnie bardziej odpowiednie do wdrożenia aplikacji, gdy nastąpi niewielkie przeładowanie lub nie zostanie wykonane żadne ponowne ładowanie, ale udowodni, że przeciąga się, gdy chce wprowadzić wiele drobnych zmian .
Niektóre materiały mam pod ręką na temat kompilacji kodu Clojure mniej więcej kronologicznie według kolejności publikacji, ponieważ Nicholas wpłynął na moją pracę z GSoC.
Które przypuszczam pozostawia mnie nieszczęśliwe miejsce powiedzenia po prostu "Przepraszam, Scala nie została zaprojektowana w ten sposób C lojure było "w odniesieniu do szyfrowania wymiany".
Jeden jest używany do pisania Clojure, drugi do pisania Scala. Ponadto: http://stackoverflow.com/questions/2471947/is-there-an-easy-way-to-get-the-scala-repl-to-reload-a-class-or-package – vptheron
Trochę trudno bym wiedział, jak będzie wyglądała poprawna odpowiedź? Być może pytasz, czy Scala REPL może ponownie zdefiniować funkcje w uruchomionym programie? –
Ciekawość, pytanie jest dobre, ale tytuł nie jest. – Mars