¿La sintaxis de los lenguajes de programación depende de su implementación?

12

Aunque, mi pregunta puede ser completamente irrelevante, pero he sentido un patrón entre la mayoría de los lenguajes de programación y sus implementaciones oficiales.

Los lenguajes interpretados (¿interpretados por byte?) Como Python, Lua, etc. generalmente tienen una sintaxis extremadamente indulgente y fácil y generalmente no tienen tipo o no requieren que el desarrollador escriba explícitamente tipos de variables en el código fuente;

Los lenguajes compilados como C, C ++, Pascal, etc. generalmente tienen una sintaxis estricta, generalmente tienen tipos y en su mayoría requieren más tiempo de código / desarrollo

Los lenguajes cuyas implementaciones oficiales están compiladas en JIT como Java / C # suelen ser un compromiso único entre los dos anteriores con algunas de las mejores características de ambos.

Algunos de los lenguajes de programación compilados más modernos como D y Vala (y la implementación GNU GJC de Java) son quizás una excepción a esta regla y se parecen a la sintaxis y las características de los lenguajes compilados JIT como Java y C #.

Mi primera pregunta es, ¿es esto realmente relevante? ¿O es solo una coincidencia que la mayoría de los idiomas interpretados tienen una sintaxis fácil, los compilados JIT tienen una sintaxis moderada y características, etc.

En segundo lugar, si esto no es una coincidencia, ¿por qué es así? Como, por ejemplo, ¿algunas características solo pueden implementarse en un lenguaje de programación si, por ejemplo, está compilando JIT?

AprendizHacker
fuente
@YannisRizos lo siento, no es una cita. Solo quería resaltarlo. Lo editaré
ApprenticeHacker
1
Genial, pensé que no era una cita, pero podría hacer que los respondedores pensaran que era una y no tratar de refutarla (o estar ciegamente de acuerdo con ella) ... He notado patrones similares pero desafortunadamente no tengo un buen responder.
yannis
@ R.MartinhoFernandes lo siento, no estaba al tanto de eso. Lo editaré (nuevamente).
ApprenticeHacker
44
Perl se tipea dinámicamente para los tipos definidos por el usuario, estáticamente tipado con respecto a distinguir matrices, hashes, escalares y subrutinas, y tipado fuertemente mediante el uso estricto, interpretado y compilado JIT (no al mismo tiempo, por supuesto) ... Siempre que alguien lo intente para darle sentido al diseño del lenguaje,
incluir
3
¿Qué quiere decir con "sintaxis indulgente" frente a "sintaxis estricta"? Todos son lenguajes formales y ninguno ejecutará código fuente con errores de sintaxis.
nikie

Respuestas:

17

No hay conexión alguna entre semántica y sintaxis. Los lenguajes compilados homoicónicos como Scheme vienen con una sintaxis bastante minimalista. Los metalenguajes compilados de bajo nivel como Forth son aún más simples que eso. Algunos lenguajes compilados estrictamente tipados se basan en una sintaxis trivial (piense en ML, Haskell). OTOH, la sintaxis de Python es muy pesada, en términos de una serie de reglas de sintaxis.

Y sí, escribir no tiene nada que ver con la sintaxis, está en el lado semántico de un lenguaje, a menos que sea algo tan pervertido como C ++, donde ni siquiera se puede analizar sin tener toda la información de escritura disponible.

Una tendencia general es que los lenguajes que evolucionaron durante demasiado tiempo y no contenían ninguna protección de diseño contra las desviaciones de sintaxis, tarde o temprano evolucionarían en abominaciones sintácticas.

SK-logic
fuente
+1 por hacerme buscar "homoiconic" ... Y por el sutil guiño a PHP ...
yannis
1
+1, lenguajes que evolucionaron durante demasiado tiempo y no contenían ninguna protección de diseño , ¿esto también se refiere a Delphi / Object-Pascal?
ApprenticeHacker
1
@ ThomasEding, te equivocas. La misma semántica se puede implementar sobre una amplia gama de estilos de sintaxis, incluso con un lenguaje sin sintaxis (como Lisp o Forth). Se puede usar la misma sintaxis con una gran variedad de semánticas diferentes; por ejemplo, la sintaxis de las expresiones C y Verilog es casi la misma, pero la semántica es dramáticamente diferente.
SK-logic
1
@ SK-logic: el hecho de que sea complejo y Turing completo no significa que no sea al menos una parte muy importante de la sintaxis del programa. Analizar varios idiomas es Turing completo, eso no hace que el análisis mágico sea algo que no tiene "nada que ver con la sintaxis". La sintaxis no se trata de "alcance", se trata de reglas para la estructura de las declaraciones en un lenguaje, sin decir nada sobre el significado de esas declaraciones. La verificación de tipos y la inferencia de tipos operan en árboles de sintaxis de programas sin ejecutarlos: determinan cosas sobre la estructura del programa sin decir nada sobre ...
Jack
1
@ Jack, estás tratando de redefinir qué es la sintaxis. No hay lenguajes prácticos que necesiten un analizador completo de Turing, la mayoría no son más que libres de contexto. Y aquí es donde debe quedar la sintaxis. No extienda esta noción (ya demasiado estirada) en ningún otro lugar. Y ya mencioné el isomorfismo de Curry-Howard: se trata de semántica, mucho más allá de las meras reglas de corrección. Creo que el mismo término " type checking" es extremadamente contraproducente y no debe usarse, es muy engañoso, no refleja la naturaleza de los sistemas de tipos.
SK-logic
6

Sobre todo esto es una coincidencia.

Los lenguajes de programación han evolucionado con el tiempo y la tecnología de compiladores e intérpretes ha mejorado. La eficiencia del procesamiento subyacente (es decir, el tiempo de compilación, la sobrecarga de interpretación, el tiempo de ejecución, etc.) también es menos importante a medida que las plataformas informáticas convencionales han crecido en potencia.

La sintaxis del lenguaje hace tener un impacto - por ejemplo, Pascal fue diseñado con mucho cuidado por lo que podría utilizar un único pase compilador - es decir, un pase sobre la fuente y tiene código de máquina excutable. Ada, por otro lado, no prestó atención a esto, y los compiladores de Ada son notoriamente difíciles de escribir, la mayoría requiere más de un pase. (Un muy buen compilador Ada que utilicé hace muchos años fue un compilador de 8 pases. Como se puede imaginar, fue muy lento).

Si observa idiomas antiguos como Fortran (compilado) y BASIC (interpretado o compilado), tienen / tenían una sintaxis muy estricta y reglas semánticas. [En el caso de BASIC, eso no es Bills old BASIC, debe volver antes al original.]

Por otro lado, mirando otras cosas más antiguas como APL (un montón de diversión) esto tenía una tipificación dinámica, más o menos. También se interpretó generalmente, pero también se pudo compilar.

La sintaxis de Lenient es difícil: si eso significa que tiene cosas que son opcionales o que se pueden inferir, significa que el idioma tiene la riqueza suficiente para poder eliminarlo. Por otra parte, BASIC tenía eso hace muchos años cuando la declaración "LET" se convirtió en opcional.

Muchas de las ideas que ve ahora (por ejemplo, mecanografía sin tipo o dinámica) son en realidad muy antiguas: aparecieron por primera vez en los años 70 o principios de los 80. La forma en que se usan y los idiomas en que se usan estas ideas han cambiado y crecido. Pero fundamentalmente, gran parte de lo nuevo es en realidad cosas viejas vestidas con ropa nueva.

Aquí hay algunos ejemplos fuera de mi cabeza:

  • APL: tipeo dinámico. Generalmente interpretado. Vino de los años 1960/70.
  • BÁSICO: escritura fuerte o dinámica. Interpretado o compilado. 1970 y muchos más allá.
  • Fortran: mecanografía fuerte. Compilado 1960 o antes.
  • Algol68: mecanografía fuerte. Compilado 1960's.
  • PL / 1: mecanografía fuerte. Compilado 1960's.
  • Pascal: mecanografía fuerte. Compilado 1970's. (¡Pero en la década de 1980 había compiladores del sistema P muy similares a los compiladores JIT!)
  • Algunas implementaciones de Fortran y otras por DEC en los primeros días fueron parcialmente compiladas y parcialmente interpretadas.
  • Smalltalk: mecanografía dinámica. Compilado a bytecode que se interpreta. 1980's.
  • Prólogo: más extrañeza. Funcional. Compilado (Turbo Prolog, ¿alguien?). 1980's.
  • C: tipificación fuerte (ja, ja). Compilado 1960 ... hoy.
  • Ada: mecanografía súper fuerte. Compilado 1980's.
  • Perl: escritura dinámica. (Sintaxis fuerte). Interpretado. 1990 (?).

Podría seguir.

  • Esquina Nitpickers: Muchos lenguajes interpretados se tokenizan o "compilan byte" en el momento en que se carga / lee la fuente. Esto hace que la operación posterior del intérprete sea mucho más simple. A veces puede guardar la versión del código compilada en bytes. A veces no puedes. Aún se interpreta.

Actualización: porque no estaba lo suficientemente claro.

Escribir puede variar ampliamente.

La tipificación estática fija en tiempo de compilación es común (p. Ej., C, Ada, C ++, Fortan, etc., etc.). Aquí es donde declaras una COSA de TIPO y es así para siempre.

También es posible tener una escritura dinámica, donde la cosa recoge el tipo que se le asigna. Por ejemplo, PHP y algunos principios básicos, y APL, donde asignaría un número entero a una variable y de ahí en adelante era un tipo entero. Si luego le asignó una cadena, entonces era un tipo de cadena. Y así.

Y luego hay una escritura suelta, por ejemplo PHP, donde puedes hacer cosas realmente extrañas como asignar un número entero (entre comillas, por lo que es una cadena) a una variable y luego agregarle un número. (por ejemplo, '5' + 5 daría como resultado 10). Esta es la tierra de lo extraño, pero también a veces muy útil.

SIN EMBARGO, estas son características diseñadas en un lenguaje. La implementación solo hace que eso suceda.

rápidamente_ahora
fuente
13
La escritura fuerte no es la contrapartida de la escritura dinámica. Es la contrapartida del tipeo débil. La contraparte de la tipificación dinámica es la tipificación estática: en una, los tipos de expresiones en un programa pueden conocerse estáticamente (es decir, sin ejecutar el programa); en otro, los tipos solo pueden conocerse dinámicamente (es decir, el programa debe ejecutarse).
R. Martinho Fernandes
Sí, y ambas variantes de BASIC y APL estaban haciendo esto a fines de la década de 1970. Los tipos de APL no son exactamente como los entendemos hoy (son cosas como enteros / flotantes de tipo universal pero también pueden ser vectores, cadenas y matrices multidimensionales).
rapid_now
Un intérprete de Fortran todavía se usa ampliamente (ver Cernlib y PAW). Y su descendiente, ROOT, se basa en un intérprete de C ++.
SK-logic
No estoy del todo claro cómo la tipificación fuerte / débil y estática / dinámica se relaciona con la sintaxis, para ser sincero. Pero la calidad de respuesta fue bastante buena, por lo que estoy evitando la votación. Escribiría la clase C como "estático / débil" (es trivial mirar un valor almacenado como si fuera otro tipo, posiblemente obteniendo el valor incorrecto).
Vatine
@Vatine: en realidad diría fuerte en tiempo de compilación, no existente en tiempo de ejecución, si así lo desea. Puede hacerlo utilizando punteros y su equivalente en muchos idiomas. Incluso es posible en pascal clásico usando registros de variantes, y en Ada usando UNCHECKED_CONVERSION (aunque difícil, es posible).
rapid_now
2

Creo que es al revés: la implementación depende de la sintaxis. Por ejemplo, si su sintaxis permite la reflexión, entonces la implementación debe proporcionar un tiempo de ejecución que lo admita.

Apilado
fuente
@IntermediateHacker: pero está en Java, así que debería ser increíble
sehe
2

Generalmente estoy de acuerdo con rapid_now en que su observación es principalmente un resultado de la historia. Dicho esto, el razonamiento subyacente se reduce a algo como esto:

The more modern a language is, the more comfortable it should be to use.

(No es una cita realmente, solo mi propia formulación). Cuando escribo comfortableaquí, me refiero a lo que usted llamó best features of both. Más precisamente, no quiero hablar a favor o en contra de la escritura estática / dinámica o la sintaxis estricta / indulgente. En cambio, es importante ver el enfoque puesto en los desarrolladores y aumentar su nivel de comodidad al trabajar con el lenguaje.

Aquí hay algunas razones que no se han mencionado en las respuestas anteriores, que pueden proporcionarle algunas ideas de por qué observa estas cosas (y están basadas en la historia del desarrollo del lenguaje de programación):

  • Tenemos cientos de lenguajes de programación en estos días. Cuando surge una nueva, ¿cómo puede encontrar una audiencia amplia? Esta es la razón principal por la cual los nuevos lenguajes siempre intentan aumentar el nivel de comodidad de los desarrolladores. Si el idioma puede hacer lo mismo que el anterior, pero puede hacerlo mucho más fácil / más simple / más elegante / etc. es posible que desee considerar cambiar realmente.

  • La curva de aprendizaje va de la mano con eso. En el pasado, teníamos pocos idiomas y valía la pena invertir tiempo para aprender uno. Incluso si eso significaba invertir mucho tiempo. La comodidad vuelve a aumentar si se te ocurre un lenguaje que los desarrolladores puedan aprender muy rápidamente. La complejidad de cualquier tipo (por ejemplo, sintaxis complicada involucrada) es perjudicial para esto y, por lo tanto, se reduce cada vez más en los idiomas más nuevos.

  • Los avances tecnológicos (una razón histórica directa aquí) son responsables de que los creadores de compiladores ahora puedan centrarse más en la comodidad del desarrollador. En los primeros días, estábamos felices de poder construir un compilador. Sin embargo, eso a menudo implicaba fuertes restricciones. A medida que aumentó el conocimiento tecnológico, pudimos levantar estas restricciones nuevamente.

Entonces, en general, los lenguajes de programación y los compiladores han visto un desarrollo similar al de las aplicaciones típicas de usuario final:

  1. Etapa inicial: es algo genial, pero la tecnología de punta apenas lo hace funcionar a costa de comodidad / facilidad de uso / lo que no.
  2. Mejora tecnológica: podemos construir estas cosas de manera más robusta, más rápida y más fácil.
  3. El enfoque se dirige al usuario: de manera similar al movimiento Web2.0 que se enfoca en la experiencia del usuario, los nuevos lenguajes de programación se enfocan en la perspectiva del desarrollador.
Franco
fuente
(Not a quote really, just my own formulation.)Bueno, lo formateó como código, no como una cita en
bloque
3
La comodidad depende claramente de un gusto (que siempre es completamente subjetivo). El idioma con el que me siento más cómodo fue diseñado en 1959, y no puedo soportar tratar con algunos de los idiomas que aparecieron en este siglo.
SK-logic
1
La comodidad también depende del propósito. Ejecutar PHP o Prolog en un micro integrado de 8k para un controlador de lavadora podría ser "cómodo" de programar, pero también muy difícil de hacer que se ajuste y funcione con un rendimiento aceptable.
rapid_now
0

Un lenguaje de programación dado puede o no exponer o restringir suficiente información semántica para que un compilador deduzca cómo reducirlo a código ejecutable sin decisiones adicionales de tiempo de ejecución ("¿qué tipo es esta variable?", Etc.) Algunos lenguajes están explícitamente diseñados para hacer Esta restricción es obligatoria o fácil de determinar.

A medida que los compiladores se vuelven más inteligentes, podrían adivinar o perfilar suficiente información para generar código ejecutable para la (s) ruta (s) más probable (s) incluso para idiomas que no fueron diseñados explícitamente para exponer o restringir esas decisiones.

Sin embargo, los idiomas donde el código (evalString ()) se puede crear o ingresar en tiempo de ejecución (y otras cosas que el compilador no puede deducir ni adivinar) pueden requerir un intérprete o compilador JIT para estar disponible en tiempo de ejecución, incluso con intentos de compilarlos.

En el pasado, un lenguaje de programación y su implementación podrían haber evolucionado para ajustarse a alguna restricción de hardware, como si el intérprete podría caber en 4k o 16k, o si el compilador podría terminar en menos de un minuto de tiempo de CPU. A medida que las máquinas se vuelven más rápidas, es posible (re) compilar algunos programas interpretados anteriormente tan rápido como el programador puede presionar la tecla de retorno, o interpretar el código fuente del programa compilado anteriormente más rápido de lo que el hardware un poco más antiguo podría ejecutar ejecutables compilados optimizados.

hotpaw2
fuente