Co sprawia, że ​​JVM jest tak wszechstronny, że obsługuje tak wiele języków JVM?

18

JVM obsługuje tak wiele języków innych niż Java, jak Groovy,Clojure,Scalaitp., Które są językami funkcjonalnymi w przeciwieństwie do Javy (mam na myśli Javę przed wersją 8, gdzie Lambda'snie są obsługiwane), która nie obsługuje funkcji funkcjonalnych. Na wysokim poziomie, co sprawia, że ​​JVM jest tak wszechstronny, że może obsługiwać zarówno języki obiektowe, jak i funkcjonalne?

Maniak
źródło
„Groovy, Clojure, Scala itp., Które są funkcjonalne”. Niektóre z nich są bardziej funkcjonalne niż inne. Używałbym skali z Groovy najmniej funkcjonalnym i Clojure najbardziej, ze Scalą pośrodku.
Vorg van Geir

Odpowiedzi:

37

W porównaniu z innymi maszynami wirtualnymi, JVM nie jest szczególnie wszechstronny . Obsługuje bezpośrednio statyczne OO. Jeśli chodzi o wszystko inne, musisz zobaczyć, jakich części możesz użyć i jak zbudować wszystko inne, czego twój język potrzebuje na tych częściach.

Na przykład, dopóki Java 7 nie wprowadziła invokedynamickodu bajtowego, bardzo trudno było wdrożyć dynamicznie typowany język OO w JVM - trzeba było zastosować złożone obejścia, które były złe dla wydajności i skutkowały strasznie rozdętymi śladami stosu.

A jednak przed JVM zaimplementowano kilka dynamicznych języków (między innymi Groovy, Jython, JRuby).

Nie dlatego, że JVM jest tak wszechstronny, ale dlatego, że jest tak rozpowszechniony i ponieważ ma bardzo dojrzałe, dobrze obsługiwane i wydajne implementacje.

A może nawet ważniejsze, ponieważ istnieje ogromna ilość kodu Java, który robi prawie wszystko, a jeśli twój język działa na JVM, możesz łatwo zaoferować możliwości integracji z tym kodem. Zasadniczo obsługa języka w JVM jest wersją XXI wieku oferującą współdziałanie z C.

Michael Borgwardt
źródło
Dobra odpowiedź (+1). Ostatni punkt, o którym wspominasz, jest również odpowiedzialny za popularność języka Java jako języka: w końcu posiadanie ogromnej ilości kodu, którego można użyć ponownie za darmo, może zaoszczędzić znacznie więcej czasu niż możliwość korzystania z najnowszego i najmodniejszego języka cechy.
Giorgio
4

JVM został napisany tak, aby zachowywał się jak procesor, istnieje zestaw instrukcji, coś w rodzaju zestawu, który uruchamia VM nazywa się bajtecodes. Jeśli możesz napisać kompilator, który generuje prawidłowy zestaw kodów bajtowych, JVM może je uruchomić.

Wikipedia ma listę kodów bajtowych:

http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings

a także wyjaśnienie, w jaki sposób JVM ładuje kody bajtów:

http://en.wikipedia.org/wiki/Java_virtual_machine

Używając kodów bajtowych stylu wywołania, funkcjonalny język może wykonywać kod, niezależnie od tego, jak wygląda źródło. Ponadto, dzięki dodaniu invokevirtual, implementacje języka, takie jak jruby, dają pewną elastyczność w sposobie ich działania.

Sasbury
źródło
1
To samo dotyczy każdej innej maszyny wirtualnej: VM YARV Ruby, Rubinius Ruby VM, CPython VM (która przecież poprzedza JVM), Parrot, różnych Smalltalk i Lisp VM, i oczywiście Pascal P- System kodu, po którym modelowana jest JVM.
Jörg W Mittag
Uzgodniony, JVM zdecydowanie nie jest pierwszą maszyną wirtualną. Myślę, że JVM jest popularny w innych językach, ponieważ Java jest popularny, VM jest aktywnie rozwijany i dobrze udokumentowany.
sasbury
2

Dodam, że JVM obsługuje dobrze zdefiniowany i całkiem przyzwoity model pamięci ( JMM ), co oznacza dobre wsparcie dla spójnego (choć niskiego poziomu) zachowania wątków. Ma także potężny kompilator Just In Time (nieużyteczny dla języków dynamicznych dzięki MethodHandles i invokedynamic).

Ostatni, ale nie mniej ważny, jest podsystem JVM Garbage Collection, który (z odpowiednim strojeniem) zarządza pamięcią dla ciebie niezależnie od języka na górze.

Martijn Verburg
źródło
JMM jest jedną z moich najmniej ulubionych rzeczy na temat Javy. Jestem fanem efektywnie niezmiennych danych (np. Tablic, których zawartość nigdy się nie zmieni po tym, jak będą widoczne dla innych wątków), ale otrzymałem takie zdanie, jak someField = new int[]{42};jedyny sposób na zapewnienie, że każdy wątek, który widzi nową tablicę, zobaczy wartość 42 mają albo zrobić pole, finalalbo volatile. Jeśli pole jest generowane leniwie, ale jest często używane, sprawiając, że nie finalbędzie działać, a volatilenałożenie go może nałożyć niepotrzebną karę synchronizacyjną za każdym razem, gdy jest dostępne. W nawet
najluzszym
... kod może zażądać, aby zapełnianie tablicy nastąpiło przed zapisaniem odwołania. Inne wątki, które czytają pole, mogą, ale nie muszą, widzieć odwołanie do nowej tablicy, ale nie ponoszą żadnych kosztów dla siebie, że jeśli zobaczą nową tablicę, zobaczą jej zawartość.
supercat
1

Kluczowym elementem w tym jest oddzielenie kompilacji od fazy wykonania. Dzięki temu możliwe jest pisanie innych kompilatorów kompilujących inne języki do kodu bajtowego.

Bajtek tam działa podobnie jak kod maszynowy procesora - masz wszystkie małe operacje potrzebne do uruchomienia programu - możesz uzyskać zmienną, wykonać matematykę, wykonać operacje warunkowe itp.

Java również nie jest wyjątkowa. W Javie istnienie wielu języków nie było nawet celem projektowym, w przeciwieństwie do innych maszyn wirtualnych. Dla .NET CIL Microsoftu możliwość uruchamiania wielu języków (C #, VB.Net, ...) była kluczowym elementem projektu, również ParrotVM z projektu Perl6, który miał być ogólną maszyną wirtualną.

Dla zabawy stworzyłem kiedyś dowód, że nawet PHP Zend Engine na to pozwoli.

I szczerze mówiąc, nie jest to nic nowego - nawet na prawdziwym sprzęcie możesz obsługiwać wiele języków - np. C lub Fortran.

Różnica w stosunku do tego oddzielenia od kompilacji i wykonywania to interpretatory klasyczne, takie jak niektóre formy Basic, skrypty powłoki itp., Często działają w taki sposób, że wykonują kod mniej więcej wiersz po wierszu, nie wprowadzając go w natychmiastową formę pomiędzy.

Johnnes
źródło
1

JVM jest pierwszą maszyną wirtualną, o której wiem, która kombinacja wyrzucania elementów bezużytecznych, wydajność i działający model piaskownicy. Pojawienie się wielu języków do obsługi JVM prawdopodobnie nie jest tak bardzo wynikiem „wszechstronności”, ale raczej faktu, że język Java nie ma pewnych istotnych funkcji, które ludzie chcą w języku programowania. Na przykład, podczas gdy większość języków maszynowych ma tylko pół tuzina typów danych (np. Bajt, półsłówko, słowo, podwójne słowo, liczba zmiennoprzecinkowa pojedynczej precyzji i liczba zmiennoprzecinkowa podwójnej precyzji), ogromna większość języków programowania pozwala na użycie kodu dowolna liczba typów danych zdefiniowanych przez użytkownika. JVM rozpoznaje kilka prymitywnych typów podobnych do tych na typowej maszynie, a także jeszcze jeden typ: Promiscuous Object Reference. Język Java również rozpoznaje te prymitywy, i Odwołania do obiektów rozwiązłych. Podczas gdy zmienna może być ograniczona tak, aby nie zawierała odniesień do niczego, co nie jest określoną klasą, język nie rozróżnia żadnego z następujących rodzajów pola typuList<String>który może być przechowywany przez MyThingklasę instancji MyClass:

  • Odniesienie do czegoś, co kod wie, jest niezmienną implementacją List<String>

  • Odwołanie do instancji typu listy zmiennych, która nigdy nie będzie narażona na nic, co mogłoby ją mutować.

  • Odwołanie do zmiennej listy, do której, oprócz wykonywania MyThingsmetod, żadne inne odniesienie nie mogłoby istnieć nigdzie we wszechświecie.

  • Odwołanie do listy zmiennych, która jest własnością innego obiektu , którego ten obiekt chciałby MyThingużyć w pewien sposób.

  • Odniesienie do listy zmiennych, która MyThingjest właścicielem, ale która również wystawiła na działanie innych obiektów, aby mogli coś z tym zrobić.

Mimo że wszystkie te pola mogą mieć typ List<String>, zawierają bardzo różne rzeczy. Wyrazisty język może pozwolić na rozróżnienie tych znaczeń, ale Java tego nie robi. Ponieważ język może nadawać znaczenie takim rzeczom (przynajmniej poza ogólnymi kontekstami) i działać w JVM, pozostawia to wiele miejsca dla języków docelowych dla JVM do wyrażania pojęć, których Java nie może.

supercat
źródło