Durante muchos años nos enseñaron que existían dos tipos de lenguajes:
- Lenguajes compilados.
- Lenguajes interpretados.
Aunque esta clasificación fue útil durante mucho tiempo, hoy resulta demasiado simplista.
Lo que realmente existen son distintas estrategias para traducir y ejecutar un programa.
1. Compilación Ahead of Time (AOT)
El código fuente se traduce completamente a código máquina antes de ejecutarse.
Código fuente
│
▼
Compilador
│
▼
Código máquina
│
▼
Ejecución
Es la estrategia utilizada tradicionalmente por lenguajes como C, C++ o Rust.
2. Interpretación
El programa es leído y ejecutado por un intérprete, sin generar previamente un ejecutable nativo.
Código fuente
│
▼
Intérprete
│
▼
Ejecución
Es el modelo clásico de lenguajes como Bash, AWK o las primeras implementaciones de muchos lenguajes de scripting.
3. Compilación a bytecode + intérprete
En lugar de ejecutar directamente el código fuente, primero se genera una representación intermedia (bytecode).
Luego, una máquina virtual interpreta ese bytecode.
Código fuente
│
▼
Compilador
│
▼
Bytecode
│
▼
Máquina Virtual
│
▼
Intérprete
│
▼
Ejecución
Este enfoque permite que el mismo programa pueda ejecutarse en distintas plataformas sin volver a compilar el código fuente.
CPython y las primeras versiones de la JVM son ejemplos clásicos.
4. Bytecode + intérprete + JIT
La mayoría de los runtimes modernos utilizan una estrategia híbrida.
Primero generan bytecode.
Luego comienzan interpretándolo.
Mientras el programa se ejecuta, el runtime identifica las partes más utilizadas ("hot code") y las compila dinámicamente a código máquina mediante un compilador **Just-In-Time (JIT)**.
Código fuente
│
▼
Bytecode
│
▼
Máquina Virtual
│
├── Interpreta
│
└── Compila con JIT
│
▼
Código máquina
Esta estrategia combina:
- un inicio rápido,
- portabilidad,
- y optimizaciones que sólo son posibles cuando el programa ya está ejecutándose.
Es el enfoque utilizado por la JVM HotSpot, .NET CLR, V8 (JavaScript) y PyPy.
Entonces... ¿un lenguaje es compilado o interpretado?
En realidad, esa pregunta ya no es la más adecuada.
Los lenguajes definen una sintaxis y una semántica.
Quienes deciden cómo ejecutar un programa son sus implementaciones.
Por ejemplo:
- Java HotSpot: Bytecode + Intérprete + JIT
- Java GraalVM Native Image: AOT
- Python CPython: Bytecode + Intérprete
- Python PyPy: Bytecode + Intérprete + JIT
- JavaScript V8: Bytecode + Intérprete + JIT
- C con GCC/Clang : AOT
Por eso, decir que Java es compilado o que Python es interpretado es una simplificación.
Lo más preciso es hablar de estrategias de traducción y ejecución, porque un mismo lenguaje puede tener distintas implementaciones que ejecutan el mismo programa de maneras completamente diferentes.
La informática evoluciona constantemente, y nuestras clasificaciones también deberían hacerlo.
