O que torna a JVM tão versátil para suportar tantos idiomas da JVM?

18

A JVM suporta tantas linguagens que não Java, como Groovy,Clojure,Scalaetc, que são linguagens funcionais diferentes do Java (refiro-me ao Java antes da Versão 8, onde Lambda'snão são suportadas) que não suportam recursos funcionais. Em um alto nível, o que torna a JVM tão versátil que pode suportar idiomas orientados a objetos e funcionais?

Nerd
fonte
"Groovy, Clojure, Scala etc que são funcionais". Alguns são mais funcionais que outros. Eu usaria uma balança com Groovy, o menos funcional, e Clojure, com Scala no meio.
Vorg van Geir 11/11

Respostas:

37

Comparada a outras VMs, a JVM na verdade não é particularmente versátil . Ele suporta diretamente OO digitado estaticamente. Para todo o resto, é necessário ver quais partes você pode usar e como criar tudo o que seu idioma precisa sobre essas partes.

Por exemplo, até que o Java 7 introduzisse o invokedynamicbytecode, era muito difícil implementar uma linguagem OO de tipo dinâmico na JVM - era necessário usar soluções alternativas complexas que apresentavam problemas de desempenho e resultavam em rastreios de pilha horrivelmente inchados.

E, no entanto, várias linguagens dinâmicas (Groovy, Jython, JRuby entre outras) foram implementadas na JVM antes disso.

Não porque a JVM é muito versátil, mas porque é muito difundida e porque possui implementações muito maduras, bem suportadas e de alto desempenho.

E, talvez ainda mais importante, porque há uma enorme quantidade de código Java por aí fazendo praticamente qualquer coisa e, se sua linguagem é executada na JVM, você pode oferecer facilidades facilmente para integrar-se a esse código. Basicamente, ter seu idioma rodando na JVM é a versão do século XXI de oferecer interoperabilidade com C.

Michael Borgwardt
fonte
Boa resposta (+1). O último ponto que você menciona é o IMHO também responsável pela popularidade do Java como linguagem: no final, ter uma quantidade enorme de código que você pode reutilizar gratuitamente pode economizar muito mais tempo do que poder usar a linguagem mais recente e elegante. características.
Giorgio
4

A JVM foi escrita para agir basicamente como uma CPU, há um conjunto de instruções, como o assembly, que a VM executa chamado bytecodes. Se você puder gravar um compilador que gere um conjunto válido de bytecodes, a JVM poderá executá-los.

A Wikipedia possui uma lista dos bytecodes:

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

bem como uma explicação de como a JVM carrega os códigos de bytes:

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

Ao usar os bytecodes de estilo de chamada, uma linguagem funcional pode executar código, independentemente da aparência da fonte. Além disso, com a adição de invokevirtual, implementações de linguagem como o jruby têm proporcionado alguma flexibilidade na forma como são executadas.

Sasbury
fonte
1
O mesmo se aplica a todas as outras VMs existentes: a YARV Ruby VM, a Rubinius Ruby VM, a CPython VM (que antes é anterior à JVM), Parrot, várias VMs Smalltalk e Lisp e, claro, o Pascal P- Sistema de código, após o qual a JVM é modelada.
Jörg W Mittag
Concordado, a JVM definitivamente não é a primeira VM disponível no mercado. Eu acho que a JVM é popular para outras linguagens porque Java é popular, a VM é ativamente desenvolvida e bem documentada.
sasbury
2

Acrescentarei que a JVM suporta um JMM (Modelo de Memória ) bem definido e bastante decente, o que significa um bom suporte para um comportamento de encadeamento consistente (embora de baixo nível). Ele também possui um poderoso compilador Just In Time (não é mais útil para linguagens dinâmicas, graças a MethodHandles e invokedynamic).

Por último, mas não menos importante, é o subsistema de coleta de lixo da JVM que (com o ajuste correto) gerencia a memória para você, independentemente do idioma no topo.

Martijn Verburg
fonte
O JMM é uma das minhas coisas menos favoritas sobre Java. Sou fã de dados efetivamente imutáveis ​​(por exemplo, matrizes cujo conteúdo nunca será alterado após serem visíveis para outros threads), mas recebi uma declaração como someField = new int[]{42};as únicas maneiras de garantir que qualquer thread que veja a nova matriz veja o valor 42 são para fazer o campo finalou volatile. Se o campo for gerado preguiçosamente, mas acessado com frequência, finalnão funcionará e volatilepoderá impor uma penalidade de sincronização desnecessária toda vez que for acessado. Até mesmo no mais fraco modelo .NET ... #
308
... o código pode solicitar que a população da matriz ocorra antes do armazenamento da referência. Outros threads que lêem o campo podem ou não ver a referência à nova matriz, mas sem nenhum custo para si mesmos, de que, se virem a nova matriz, verão seu conteúdo.
Supercat 04/02
1

O elemento chave nisso é a separação da compilação da fase de execução. Com isso, é possível escrever outros compiladores compilando outros idiomas no bytecode.

O bytecode atua de maneira semelhante ao código de máquina de uma CPU - você tem todas as pequenas operações necessárias para executar um programa - você pode obter uma variável, fazer contas nela, realizar operações condicionais etc.

Java também não é especial. Em Java, a existência de várias linguagens não era nem uma meta de design, ao contrário de outras VMs. Para o .Net CIL da Microsoft, a capacidade de executar vários idiomas (C #, VB.Net, ...) era um elemento-chave de design, também o ParrotVM do projeto Perl6 pretendia ser uma VM genérica.

Por diversão, criei uma prova de que até o Zend Engine do PHP permitiria isso.

E, francamente, isso não é novidade - mesmo em hardware real, você pode executar vários idiomas - ou seja, C ou Fortran.

A diferença para essa separação da compilação e execução são os intérpretes clássicos, como algumas formas de Basic, scripts de shell etc. Eles geralmente funcionam de maneira a executar código mais ou menos linha por linha, sem trazê-lo de forma imediata. entre.

johannes
fonte
1

A JVM é a primeira máquina virtual que eu conheço, que combina coleta de lixo, desempenho e um modelo de sandbox viável. O surgimento de muitas linguagens para suportar a JVM provavelmente não resulta tanto de sua "versatilidade", mas do fato de a linguagem Java carecer de alguns recursos significativos que as pessoas desejam em uma linguagem de programação. Por exemplo, enquanto a maioria das linguagens de máquina possui apenas meia dúzia de tipos de dados (por exemplo, byte, meia palavra, palavra, palavra dupla, flutuador de precisão única e flutuador de precisão dupla), a grande maioria das linguagens de programação permite o uso de código um número arbitrário de tipos de dados definidos pelo usuário. A JVM reconhece alguns tipos primitivos semelhantes aos de uma máquina típica, além de mais um tipo: a Promiscuous Object Reference. A linguagem Java também reconhece essas primitivas, e referências promíscuas a objetos. Embora uma variável possa ser restringida a não conter referências a nada que não seja uma classe específica, o idioma não faz distinções entre nenhum dos seguintes tipos de campos do tipoList<String>que podem ser mantidos pela MyThingclasse de instância MyClass:

  • Uma referência a algo que o código sabe ser uma implementação imutável de List<String>

  • Uma referência a uma instância de um tipo de lista mutável que nunca será exposta a nada que possa sofrer uma mutação.

  • Uma referência a uma lista mutável para a qual, exceto durante a execução dos MyThingsmétodos, nenhuma outra referência poderia existir em qualquer lugar do universo.

  • Uma referência a uma lista mutável que pertence a outro objeto , que esse outro objeto gostaria MyThingde usar de alguma maneira.

  • Uma referência a uma lista mutável que MyThingpossui, mas que também foi exposta a alguns outros objetos para que eles possam fazer algo com ela.

Embora todos esses campos possam ter tipo List<String>, eles possuem coisas muito diferentes. Uma linguagem expressiva pode permitir uma distinção entre esses significados, mas Java não. Como uma linguagem pode anexar significado a essas coisas (pelo menos fora de contextos genéricos) e executada na JVM, isso deixa muito espaço para as linguagens direcionadas à JVM expressar conceitos que Java não pode.

supercat
fonte