¿Por qué no se implementó Scala con C o C ++?

28

¿Alguien sabe por qué se implementó Scala en Java y .NET en lugar de C o C ++? La mayoría de los lenguajes se implementan con Cor C ++ [es decir, Erlang, Python, PHP, Ruby, Perl]. ¿Cuáles son las ventajas para Scala implementadas en Java y .NET además de dar acceso a las bibliotecas Java y .NET?

ACTUALIZAR

¿Scala no obtendría más beneficios si se implementara en C porque se puede ajustar mejor en lugar de depender de JVM?

Joshua Partogi
fuente
18
Además, poder utilizar las bibliotecas Java existentes e interactuar estrechamente con el código Java es un GRAN beneficio, no algo menor.
Tamás Szelei
66
@OP: usted habla como si fuera malo tener un lenguaje implementado sobre la JVM (o CLR para el caso). La afinación que menciona que es posible en C no se acerca a la cantidad de afinación puesta en CLR o JVM. Y si la plataforma mejora, su idioma lo obtiene automáticamente de forma gratuita. Dada la opción, ya nadie debería implementar su lenguaje además de good'ol C en mi humilde opinión.
Chii
8
@Chii, solo admítelo, Java sigue siendo más lento que C.
Joshua Partogi
19
@jpartogi, Java no puede ser más lento o más rápido que C. Ambos son lenguajes, no sementales. En algunas condiciones específicas, algún código específico compilado por el compilador de Java y ejecutado con cierta JVM es más lento que un código más o menos comparable, generado por un compilador de C. En algunas otras condiciones, este último será más lento.
SK-logic
44
El entorno de tiempo de ejecución de Scala es un programa C ++; la JVM
mike30

Respuestas:

59

La pregunta es confusa, ya que C y C ++ son lenguajes , mientras que JVM es una máquina virtual y .Net es una plataforma . Scala podría implementarse en C o C ++, y podría generar código de máquina en lugar de código de bytes para una máquina virtual.

Respondiendo a la pregunta que se hizo:

Scala no se implementó en C o C ++ porque Scala, el lenguaje en el que se implementa realmente, es un lenguaje mucho mejor.

¿Por qué es mejor? Bueno, ve a leer sobre los objetivos de Odersky para el lenguaje Scala .

Respondiendo a la pregunta que pudo haber sido destinada:

Scala genera principalmente el código de bytes JVM porque proporciona una gran portabilidad, así como características como un recolector de basura confiable y eficiente, optimizaciones de tiempo de ejecución y compilación justo a tiempo por parte de JVM .

Permítanme repetir lo último: JVM compilará los puntos calientes del código de máquina en el código que está ejecutando. Eso es compilar al igual que los compiladores C y C ++.

Hay otras máquinas virtuales disponibles, pero Odersky, el creador de Scala, ya estaba muy familiarizado con JVM. Tenía la intención de tener CLR como alternativa, pero el esfuerzo para lograrlo aún no ha tenido éxito.

Respondiendo a la pregunta que podría / debería haberse hecho:

Compilar en código máquina no proporciona suficientes beneficios sobre compilar en código de bytes JVM.

Ciertamente es posible generar microbenchmarks en C o C ++ que superan a los equivalentes de JVM. También es cierto que el código extremadamente optimizado en C o C ++ superará el código extremadamente optimizado en Java o Scala. Sin embargo, la diferencia no es tan grande para un programa de larga duración.

Tenga en cuenta que Scala no es un lenguaje de scripting particularmente bueno precisamente porque la sobrecarga para los programas de ejecución corta es demasiado grande.

Sin embargo, en la mayoría de los casos, la velocidad de desarrollo y la facilidad de mantenimiento son más importantes que la velocidad de ejecución . En esos casos, donde las personas están más preocupadas por escribir código de muy alto nivel que es fácil de entender y cambiar, las optimizaciones de tiempo de ejecución proporcionadas por JVM pueden superar fácilmente las optimizaciones de tiempo de compilación hechas por compiladores C o C ++, haciendo JVM (y CLR ) el objetivo que realmente se ejecutará más rápido.

Entonces, no importa si la pregunta era sobre el compilador Scala como un ejecutable de código de máquina, o si los programas Scala son código de máquina, las ganancias potenciales de velocidad no necesariamente se traducen en ganancias reales de velocidad.

Y por cierto,

Te daré un contraejemplo: Haskell. Haskell genera código de máquina y, sin embargo, a los programas de Haskell les va peor en el tiroteo de Debian que en el de Scala. Dado eso, ¿alguien puede estar seguro de que los programas Scala serían más rápidos si se compilaran directamente en el código de la máquina?

Daniel C. Sobral
fuente
3
@ mike30 Scala se ejecutaría en cualquier JVM, incluso si no estuviera escrito en C ++, por lo que ese argumento no es válido. Y, en tiempo de ejecución, no hay código C ++, solo código de máquina. Sin embargo, no estoy seguro de qué se trata este comentario.
Daniel C. Sobral
3
El punto real es: generar código de máquina es bastante más complejo que generar código de bytes y requiere una implementación específica para cada sistema operativo, así como el ajuste de CPU y arquitecturas diferentes (ARM, x86, x86_64) e instrucciones avanzadas (MMX, SSE ...) Entonces de esta manera se delega a la JVM este aspecto.
Raffaello
2
Si habla tanto sobre el rendimiento de la ejecución, ¿por qué no habla sobre el rendimiento de la memoria? ¿Tienes miedo de que las cosas no salgan tan bien como imaginas?
luke1985
3
@ lukasz1985 Impulsa el rendimiento, pero la discusión sobre el rendimiento lo cubre, por lo que es irrelevante a ese respecto. Todo lo que queda es si le importa la cantidad de memoria que necesita una aplicación, y luego tiene que elegir entre GC y eso, y elegiré GC cada vez, excepto para espacios de desarrollo muy específicos, ninguno de los cuales está ocupado por Scala. Y "no es correcto decirlo a nadie" es una mierda, todos tienen ese derecho. Y aunque C / C ++ es muy relevante debido al legado, nunca se volverían populares si se hubieran lanzado en los últimos cinco años.
Daniel C. Sobral
3
@ lukasz1985 Su única evidencia de que no entiendo es que no estoy de acuerdo con usted. Una explicación alternativa a eso es que estás equivocado. Y, como alguien vivo y programando "entonces", tengo una perspectiva de primera mano sobre la toma de decisiones involucradas en elegir C y C ++ en lugar de alternativas contemporáneas, que menciono no para probar mi punto, sino para ofrecerlo como un contador al suyo: similitud para el lenguaje hablado no era de ninguna manera relevante, mientras que la similitud con el código de máquina sí lo era.
Daniel C. Sobral
31

Uno de los grandes obstáculos que enfrentan los idiomas cuando se presenta al mundo en general es la disponibilidad de la biblioteca. La respuesta tradicional a esto ha sido proporcionar una FFI (interfaz de función externa) basada en C para permitirle el acceso a bibliotecas basadas en C. Esto no es ideal por una variedad de razones, la principal de ellas:

  • Hay muchas maneras diferentes en que las bibliotecas quieren interactuar que no son compatibles con muchos lenguajes de nivel superior. Por ejemplo, si la biblioteca quiere un puntero a a struct, ¿cómo hacen frente los idiomas sin punteros Y sin structs?
  • Existen interacciones severas entre los modelos de memoria de diferentes bibliotecas e idiomas que a menudo no se pueden resolver o, si se pueden resolver, son muy propensos a errores y fallas.
  • El código de pegamento para muchas FFI no es trivial y supone un conocimiento que, de hecho, puede no ser universal. (Lo creas o no, no todos los programadores son gurús C, ¡y tampoco quieren ser ni deberían serlo!)

Esto empeora aún más con C ++. C ++ ni siquiera es compatible con C ++ (a nivel binario, quiero decir) de compilador a compilador en la misma plataforma (!), Sin mencionar otros lenguajes.

Dirigirse a la JVM resuelve muchos de estos problemas al tiempo que le brinda acceso al conjunto absolutamente enorme de bibliotecas basadas en Java. (¿Qué tan enorme? Simplemente descubra la gran selección de Apache Software Foundation para empezar.)

  • Las convenciones de llamadas y propiedad de Java son más regulares que las de C.
  • La JVM también proporciona un modelo de memoria único (incluida la recolección de elementos no utilizados) para que los idiomas y las bibliotecas interactúen. No es necesario hacer un seguimiento de quién posee qué y qué tiene que limpiar dónde. El tiempo de ejecución lo hace por ti.
  • El código de pegamento para FFI, para la mayoría de los lenguajes creados en la JVM, no existe (ya que se proporciona como un marco detrás del escenario en el lenguaje). No es necesario programar en Java, por ejemplo, para acceder a las bibliotecas de Java en Scala, Clojure, JRuby, etc. Usted accede a los objetos de Java de la misma manera que accede a los "objetos" nativos (comillas de miedo porque, por ejemplo, Clojure no tener objetos reales en el sentido OOP) y en su idioma nativo.

Además de estas ventajas, también tiene las ventajas adicionales de ejecutar en cualquier lugar que Java ejecute sin recompilación (¡pero con pruebas !: escriba una vez, pruebe en todas partes) y tenga acceso a la impresionante tecnología JIT de Java.

El CLR proporciona fortalezas similares, pero agrega lo que es una debilidad de la OMI: es prácticamente un entorno de bloqueo de proveedores. (Sí, sé sobre Mono. Todavía creo que es un entorno de bloqueo de proveedores).

SOLO MI OPINIÓN correcta
fuente
3
Te das cuenta de que C # y el CLR son en realidad un estándar abierto que cualquiera puede usar.
Erin
77
Creo que un poco acerca de dónde "sé sobre Mono" y luego "sigo pensando que es un entorno de bloqueo de proveedores" debería darte una pequeña pista, Erin.
SOLO MI OPINIÓN correcta
3
Sin embargo, @Erin no es todo el .NET Framework
alternativa
1
@alternative: si eso es demasiado bloqueo, tenga en cuenta que las pruebas de conformidad de Java aún no son gratuitas, y en el mejor de los casos es 6 de una, media docena de la otra para Java.
Deduplicador
18

Según esta entrevista , el acceso a la infraestructura y bibliotecas Java existentes fue la razón principal.

... Java es un lenguaje existente con restricciones muy difíciles. Como resultado, no podía hacer muchas cosas de la manera en que hubiera querido hacerlas, de la forma en que estaba convencido de que sería la forma correcta de hacerlas. Entonces, después de ese tiempo, cuando esencialmente el enfoque de mi trabajo era mejorar Java, decidí que era hora de dar un paso atrás. Quería comenzar con una hoja limpia y ver si podía diseñar algo mejor que Java. Pero al mismo tiempo sabía que no podía comenzar desde cero. Tuve que conectarme a una infraestructura existente, porque de lo contrario no es práctico arrancarse de la nada sin bibliotecas, herramientas y cosas así.

Entonces decidí que aunque quería diseñar un lenguaje que fuera diferente de Java, siempre se conectaría a la infraestructura de Java, a la JVM y sus bibliotecas . Esa fue la idea ...

Jeremías
fuente
10

Todos los otros idiomas que menciona, Erlang, Python, PHP, Ruby, Perl, todos fueron creados antes de Java y .NET. Si los creadores de esos lenguajes tenían el entorno de tiempo de ejecución Java o .NET disponible para ellos en ese momento, entonces es posible que los hayan aprovechado al construir su lenguaje.

Por supuesto, no puedo hablar por los desarrolladores de esos lenguajes, por lo que no puedo decir con certeza que hubieran usado .NET y / o Java al construirlos si hubieran estado disponibles, pero me parece un buena idea. Después de todo, al diseñar su lenguaje para compilar en código de bytes Java / .NET, obtiene todas las ventajas de los compiladores / optimizadores JIT, su lenguaje se ejecuta automáticamente en todas las plataformas en las que se ejecuta Java / .NET, tiene acceso a todos las bibliotecas Java / .NET, etc.

Dean Harding
fuente
2
Las ventajas descritas son algunas de las razones por las que, por ejemplo, Python se ha vuelto a implementar tanto para JVM (Jython) como para .NET (IronPython).
dancek
2
-1: Asumir que los nuevos idiomas podrían haber dependido de una plataforma específica (.Net o JVM) porque estarían disponibles no me parece un buen argumento. Por ejemplo, no veo ninguna buena razón para que Python o Erlang se ejecuten en dicha plataforma. La historia no lo dice todo.
Klaim
1
E incluso PHP nunca podría hacer lo que hace a través de JVM o .Net. @Dean Harding> No creo que IronPython o Jython hayan probado nada de valor.
Klaim
1
Lo siento, no estaba claro, lo que quise decir es que no habría tenido su "éxito" (PHP o Python) porque trabajar en una JVM o .Net implica muchas cosas que habrían molestado a muchos desarrolladores, ellos más lenguaje de nicho de lo que son actualmente. En el aspecto técnico, la plataforma (.Net o JVM) habría sido un problema porque impulsa la forma en que construye un lenguaje sobre ella. Declarar con la máquina es una forma de crear exactamente el idioma que desea. Entonces, con o sin JVM disponible, veo 0 buenas razones para construir sobre .Net y JVM. Aparte de la implementación rápida.
Klaim
2
Pequeña corrección: Java es más antiguo que PHP. Pero PHP comenzó como un programa CGI, luego se convirtió en un módulo Apache httpd y, como tal, se hizo grande. Ambas cosas (módulo cgi y httpd) no funcionan bien para Java. Entonces, las cosas no son tan fáciles, una JVM no es la plataforma para todo. ;-)
johannes
6

El código C se compila estáticamente en código nativo (código de máquina).

Scala se compila estáticamente en código de bytes de Java y luego, según sea necesario, se compila dinámicamente en código nativo optimizado. El proceso:

Código Scala --- compilado estáticamente a ---> código de byte JVM --- compilado dinámicamente por JVM-Hotspot-a ---> código nativo

Opciones generales para construir / ejecutar cualquier idioma:

  • a) interprete el código fuente directamente a través de un motor de intérprete de tiempo de ejecución
  • b) compila estáticamente código en código nativo (posiblemente a través de etapas intermedias, por ejemplo, fuente -> C -> nativo)
  • c) compila estáticamente el código fuente en un código intermedio de nivel inferior e interpreta el tiempo de ejecución
  • d) compile estáticamente el código fuente en código intermedio de nivel inferior, luego use la interpretación inicial, seguida de técnicas de compilación dinámica y optimización para convertir a código nativo. El código se interpreta hasta que se encuentran las rutas de ejecución y los cuellos de botella típicos, luego el código se compila para una ejecución más rápida en condiciones típicas. Se vuelve a compilar / volver a ajustar cuando las condiciones de ejecución cambian lo suficiente como para garantizar esto

Su pregunta: "¿Por qué Java utiliza (d) con una JVM, en lugar de (b) con el código intermedio C?"

Responder:

En primer lugar, observe que Scala es muchoLenguaje de nivel superior que C, que proporciona potencia de programación, facilidad de programación y concisión. Se trata de '1 nivel más alto' que Java debido a las funciones de primera clase y de orden superior, funciones implícitas, funciones como objetos, cierres y currículum, soporte para compilación de recursión de cola para bucles rápidos que conservan la pila, todo como objetos, todos los operadores como métodos que se puede (re) definir en bibliotecas, clases de casos y reducción (coincidencia de patrones), derivación de tipo implícito, polimorfismo más fuerte a través de rasgos expandidos multi-heredables y genéricos expandidos, sintaxis incorporada para pares y tuplas y contras (listas y árboles ) y mapas, soporte para estructuras de datos inmutables, soporte para poderosa computación 'reactiva' paralela y concurrente con copia de mensajes y paso entre actores, soporte avanzado para DSL arbitrarias específicas de dominio, capacidad de scriptabilidad y REPL. Java es aproximadamente '1 nivel superior' que C debido a la orientación a objetos, la gestión de punteros y la recolección de basura, el soporte de cadenas, el soporte de subprocesos múltiples y el control de concurrencia, además de bibliotecas API estándar.

  1. Rendimiento: para un lenguaje de alto nivel, (d) proporciona un rendimiento más rápido que (a) - (c).
    El código C escrito directamente y optimizado a mano es rápido. Sin embargo, los lenguajes de nivel superior compilados estáticamente en C son relativamente lentos. Los diseñadores de Java lo sabían bien. Su diseño actual "Hotspot" aumenta el rendimiento hasta en un orden de magnitud. En un solo núcleo, el código de Java HotSpot es en promedio '50% tan rápido 'como C optimizado para humanos (en el mejor de los casos es' 120% tan rápido ', en el peor de los casos '30% tan rápido'). Pero, por supuesto, eso es comparar manzanas con naranjas: código de bajo nivel v código de alto nivel. Y eso seria muchopeor si no se utilizó la optimización de Hotspot. Para confirmar, ¡simplemente desactive la compilación de puntos de acceso a través de los argumentos de JVM! O considere el rendimiento de Java 1 y 2, cuando el punto de acceso no existía o era inmaduro. O intente compilar otro lenguaje a través de C, por ejemplo, perlcc. Entonces, los anteriores son excelentes resultados para un lenguaje potente y productivo. Con un mayor desarrollo, es posible (o incluso probable) que JVM pronto supere en promedio a C codificado a mano. Scala es simplemente 70-80% tan lento como java en promedio. Pero scala escala fuertemente a través de múltiples núcleos (con mejoras adicionales para estar en curso), mientras que Java lo hace parcialmente y C no. El rendimiento de un solo núcleo para estos lenguajes de alto nivel está clasificado:

    interpretado <compilado estáticamente <compilado dinámicamente

    El rendimiento / escalabilidad de varios núcleos se clasifica:

    código dinámico interpretado <código imperativo compilado estáticamente <código funcional / declarativo compilado estáticamente <código funcional / declarativo compilado dinámicamente

    Esto pone a escala en el asiento ganador porque la velocidad del procesador ha alcanzado su límite y ahora la cantidad de núcleos está aumentando según la ley de Moore. Scala es muy rápido en múltiples núcleos y, en el futuro, podría ser varias veces más rápido que C o Java. Compilar estáticamente en C claramente no es la opción más rápida.

  2. Interoperabilidad: los idiomas en una máquina virtual ampliamente compatible tienen una mejor interoperabilidad de idiomas que los idiomas 'aislados'. Scala "juega automáticamente con" clases, interfaces y objetos de Java simplemente importándolos y usándolos como si fueran clases, rasgos y objetos de scala. Similar es posible con otros lenguajes JVM como Groovy, Clojure, JRuby y JPython, con una facilidad de interoperabilidad que depende de cuán limpiamente se haya hecho cada idioma para compilar en clases / interfaces / objetos de tiempo de ejecución de Java comprensibles y utilizables. Eso viene para 'gratis' (como en 'cerca de'). Scala interactúa con C a través de JNA, el sucesor de JNI, lo que conlleva cierto esfuerzo, pero las herramientas se han simplificado bastante con el tiempo. JNA en realidad puede interoperar con código nativo compilado de cualquier lenguaje arbitrario, pero debe conocer la estructura exacta de los tipos de datos y funciones compilados. Si no,

  3. Portabilidad: JVM se ejecuta en docenas de plataformas / versiones del sistema operativo 'fuera de la caja'. Scala se transfiere automáticamente a estos. La excepción notoria es iOS (iPad / iPhone / iPod), bloqueado 'comercialmente', en lugar de 'técnicamente' por Apple. Esto no podría haberse anticipado 12 años antes, durante el diseño inicial de JVM. JVM funciona bien en docenas de otros servidores, computadoras de escritorio, móviles y dispositivos integrados, incluidos los que no son compatibles con C, incluido Android con Dalvik VM adaptada por Google (más del 50% de los teléfonos nuevos vendidos). Claro, el código C funciona en una multitud de plataformas, por lo que puede clasificarse como 'a la altura o probablemente más allá' de Java (en particular, C es un subconjunto de Objective-C). Pero C vendría a costa de (1), (2) y (3). Por supuesto, la capa de presentación HTML5 / javascript / webkit (u objetivo-C) en iOS puede interactuar con una aplicación de escala remota, por lo que los desarrolladores deberían hacer eso. Por supuesto, serán menos productivos.

  4. Herramientas y bibliotecas : Obviamente, existen miles de bibliotecas y herramientas comerciales y de código abierto de Java que Scala puede aprovechar / aprovechar, más que para C.

  5. Seguridad: la ejecución en un servidor de aplicaciones controlado o en un entorno JVM brinda una mayor compatibilidad con las políticas y restricciones de seguridad, que pueden ser muy valiosas en un entorno corporativo.

Glen Best
fuente
4

JVM / CLR

El JVM (y el CLR) brindan ventajas únicas en términos de optimización y portabilidad del código.

Hasta donde yo sé, solo la versión JVM de Scala se mantiene actualizada, la versión .NET no.

Josh K
fuente
3

Parece que estás mezclando dos cosas no relacionadas.

El primero es, ¿qué lenguaje de programación utilizan los autores de Scala para implementar Scala?

A lo que la respuesta es, Scala en sí. Y es la única respuesta aceptable, realmente, porque si has inventado este nuevo lenguaje, pero no lo uses tú mismo para implementarlo, ¿para qué sirve?

Lo segundo es, ¿cuál es la plataforma de destino para ejecutar programas escritos en Scala?

Aquí la elección se vuelve más interesante, pero por ahora, el único objetivo que funciona al 100% es JVM. El soporte para .NET todavía está en progreso. Además, algunas personas están trabajando para que Scala compile en javacsript. En teoría, nada impide que alguien agregue más 'backends' para compilar en C, C ++, LLVM, código nativo o lo que sea.

¿Por qué se eligió JVM como plataforma principal? Mi conjetura es porque

  • todos quieren recolectar basura
  • gran cantidad de buenas bibliotecas listas para usar
  • gran cantidad de programadores aburridos con Java listos para saltar a algo nuevo, pero se mantienen dentro de los límites de JVM (nadie quiere migrar su código existente a otra plataforma)
artem
fuente
No veo por qué un recolector de basura no se puede implementar con C o C ++. No lo veo como una buena razón. Python lo ha hecho. Ruby lo ha hecho. Diablos, incluso Erlang lo ha hecho. ¿Quién sabe que Scala podría terminar con un mejor recolector de basura si está escrito con C o C ++?
Joshua Partogi
1
Me refería a la recolección de basura 'real'. No creo que la recolección de basura que provoca preguntas como esta sea ​​lo suficientemente buena. Incluso JVM no es lo suficientemente bueno; de lo contrario, personas como AzulSystems no podrían ganarse la vida ayudando a otras personas a superar las deficiencias de JVM.
artem
Además, bibliotecas. Es realmente difícil usar bibliotecas escritas para la gestión explícita de la memoria en un idioma con recolección de basura. Una indicación es la insistencia peculiar de la gente de Java de tener todo en 'Java puro'.
artem
0

En primer lugar, lo que supongo que realmente quería preguntar es por qué Scala no es un lenguaje compilado de manera estricta. Te diré que no lo sé. Pero también le diré que no hay razón para favorecer a JVM sobre el código nativo.

¿Por qué? La razón es simple: cualquier tecnología de virtualización necesita mucha memoria, produce una sobrecarga innecesaria y otra capa de indirección. No se trata de su implementación, es una cuestión de hecho, de la lógica que subyace detrás del concepto central de virtualización. No importa lo que hagas, SIEMPRE terminarás con características inferiores. Especialmente JVM tiene mucha memoria. Ya no es tan lento, porque tiene su propio compilador de tiempo de ejecución ejecutándose detrás de la parte posterior, pero aún así, tiene que ejecutar el proceso del compilador para poder detectar las partes más congestionadas de código y convertirlas en código binario.

Dijo que, la única razón por la que creo que estaba allí para hacer Scala JVM basado fue probablemente la popularidad del lenguaje. También supongo que hubo cierta pereza detrás de esta decisión porque es más fácil implementar un lenguaje sobre la JVM que descubrir cómo deberían verse las cosas ensambladas para trabajar en plataformas cruzadas, e incluso usar backends C existentes requiere mucho más trabajo debido al hecho que las cosas no están tan estandarizadas como con JVM.

Esa es la razón por la que puedo pensar, pero tenga en cuenta que puede haber otras razones, como problemas de licencia y políticas involucradas allí (que son cosas sucias en las que nunca me gustaría entrar).

luke1985
fuente
-2

No está claro que tener capacidad para una mejor sintonía sea una buena compensación. Las JVM pueden hacer la optimización en tiempo de ejecución, y eso suele ser al menos lo suficientemente bueno, si no superior, a lo que suele ocurrir con la compilación estática. (Obviamente, en principio, para una aplicación específica y una carga de trabajo, debería ser posible vencer a JIT con optimizaciones estáticas, pero prácticamente no tiene la carga de trabajo precisa o incluso la aplicación completa).

Bruce Stephens
fuente
esto se lee más como un comentario, ver Como respuesta
mosquito