Saltar a contenido

Práctica 1.5: Clasificación y características de los lenguajes

P15 - Clasificación y características de los lenguajes

En esta práctica compararás programas que realizan la misma suma y observarás cómo cambian su ejecución, su nivel de abstracción y la forma de organizar el código. Trabajarás con C y Python o con Java y JavaScript; después analizarás un fragmento de ensamblador y contrastarás un ejemplo orientado a objetos con una función pura. La actividad se relaciona directamente con 1.5. Lenguajes de programación y desarrolla principalmente el CE 1.e. Duración estimada: 85 minutos.

1. Objetivos

  • Clasificar lenguajes de programación según su modelo de ejecución, nivel de abstracción y paradigmas, indicando la implementación o el entorno considerado.
  • Comparar programas equivalentes y describir con evidencias las diferencias entre compilación, ejecución, abstracción y organización del código.
  • Justificar qué lenguaje o estilo puede ser adecuado para distintos contextos sin basar la decisión únicamente en etiquetas o popularidad.
  • Identificar y explicar prácticas generales de trabajo que se puedan reutilizar con otras herramientas y lenguajes.

2. Relación con RA y criterios de evaluación

Código Descripción
RA 1 Reconoce los elementos y herramientas que intervienen en el desarrollo de un programa informático, analizando sus características y las fases en las que actúan hasta llegar a su puesta en funcionamiento.
CE 1.e Se han clasificado los lenguajes de programación, identificando sus características.

El criterio principal es CE 1.e: clasificarás varios lenguajes usando ejemplos ejecutados o analizados, y justificarás las características observadas. La práctica también retoma conceptos sobre código fuente, bytecode y traductores tratados en los apartados 1.2, 1.3 y 1.4, pero no evalúa esos criterios de forma independiente.

3. Requisitos y recursos

  • Conocimientos básicos de lectura de código y uso de un editor de texto.
  • Un ordenador y acceso a las herramientas del itinerario asignado: C y Python, o Java y JavaScript. Puedes usar instalaciones locales o compiladores/entornos web que permitan ejecutar y observar el proceso.
  • Para C: compilador GCC o compatible. Para Java: JDK con javac y java. Para Python: intérprete Python 3. Para JavaScript: navegador con consola o Node.js.
  • La teoría 1.5. Lenguajes de programación. Como repaso opcional, consulta 1.2. Código fuente, objeto y ejecutable, 1.3. Código intermedio y 1.4. Traductores.
  • Trabajo en grupos de 3-4 personas. Repartid los papeles de edición, ejecución y registro de evidencias; cambiadlos entre las partes para que todas las personas participen.

Antes de empezar: la clasificación «compilado» o «interpretado» es una simplificación si no se especifica la implementación. CPython genera bytecode que ejecuta su máquina virtual; Java suele compilar a bytecode para la JVM y esta puede interpretarlo y/o usar JIT; los motores modernos de JavaScript también pueden optimizar el código con JIT. En las respuestas describe el proceso que hayas observado, no una etiqueta absoluta.

4. Pasos a seguir

4.1. Preparar los grupos y el entorno

  1. Organizad los grupos y elegid el itinerario disponible:

    • Itinerario A: C y Python.
    • Itinerario B: Java y JavaScript.

    La clase puede distribuir los dos itinerarios entre los grupos. Si falta una herramienta, utilizad un entorno web aprobado por el profesorado y anotad qué herramienta ejecutó el programa y qué pasos del proceso no pudisteis observar.

  2. Anotad el sistema operativo, el editor o IDE y las versiones de las herramientas disponibles. Por ejemplo, podéis consultar gcc --version, python --version, javac --version, java --version o node --version, según vuestro itinerario. Si ejecutáis JavaScript en un navegador, registrad el nombre y la versión del navegador.

4.2. Ejecutar la misma suma en dos lenguajes

  1. En el itinerario A, cread suma.c y suma.py con estas versiones del mismo algoritmo:

    #include <stdio.h>
    
    int main(void) {
        int num1 = 5;
        int num2 = 7;
        int resultado = num1 + num2;
        printf("El resultado es: %d\n", resultado);
        return 0;
    }
    
    num1 = 5
    num2 = 7
    resultado = num1 + num2
    print("El resultado es:", resultado)
    

    En C, compilad y ejecutad por separado. En Linux o macOS:

    gcc -Wall -Wextra -std=c11 suma.c -o suma
    ./suma
    

    En PowerShell con GCC/MinGW-w64, generad suma.exe con gcc -Wall -Wextra -std=c11 suma.c -o suma.exe y ejecutad .\suma.exe. Para Python, ejecutad python suma.py o python3 suma.py, según la instalación. Registrad los comandos exactos que hayáis usado.

  2. En el itinerario B, cread Suma.java y suma.js:

    public class Suma {
        public static void main(String[] args) {
            int num1 = 5;
            int num2 = 7;
            int resultado = num1 + num2;
            System.out.println("El resultado es: " + resultado);
        }
    }
    
    const num1 = 5;
    const num2 = 7;
    const resultado = num1 + num2;
    console.log("El resultado es:", resultado);
    

    Compilad y ejecutad Java con javac Suma.java y java Suma. Ejecutad JavaScript con node suma.js o pegad el programa en la consola de un navegador. Anotad qué herramienta interviene y qué archivos se generan.

  3. Contrastad las dos ejecuciones. Ambas deben mostrar el resultado 12. Si no coincide, comprobad que los operandos son 5 y 7, que estáis ejecutando el archivo correcto y, en C o Java, que habéis compilado la versión actualizada. Guardad las órdenes y una captura o transcripción de la salida.

  4. Comparad el proceso observado, no solo el nombre del lenguaje: ¿qué comando transforma el código antes de ejecutarlo?, ¿qué archivo o representación se obtiene?, ¿qué entorno debe estar disponible al ejecutar? Indicad también que Python, Java y JavaScript no se describen con precisión completa diciendo simplemente «no se compilan».

  5. Comprobación opcional de errores: en una copia del programa, introducid un error sintáctico pequeño (por ejemplo, quitad un punto y coma en Java o un paréntesis de cierre en C/Python/JavaScript). Registrad cuándo aparece el diagnóstico, corregidlo y repetid la ejecución. No comparéis el momento de detección como si el comportamiento fuese idéntico en todas las herramientas: los analizadores pueden detectar errores antes de ejecutar instrucciones, y los errores de ejecución son otra categoría.

4.3. Comparar alto nivel y bajo nivel

  1. Leed el fragmento en ensamblador, que representa instrucciones de estilo Intel/x86 para sumar los valores 5 y 7:

    MOV AX, 5       ; Cargar 5 en el registro AX
    ADD AX, 7       ; Sumar 7 a AX
    MOV BX, AX      ; Copiar el resultado a BX
    

    El fragmento sirve para analizar la cercanía a la máquina; no es un programa completo con entrada y salida, y no debéis ejecutarlo tal cual. El ensamblador depende de la arquitectura y de la sintaxis que admita la herramienta concreta.

  2. Comparadlo con el programa de suma de Python o Java. Completad una tabla como esta:

    Aspecto Python o Java C Ensamblador del ejemplo
    Nivel de abstracción relativo
    Operación y resultado que expresa
    Detalles de registros o máquina visibles
    Portabilidad y herramientas necesarias

    Si no habéis ejecutado C, completad esa columna a partir de la teoría. No describáis C como ensamblador ni como un lenguaje de bajo nivel absoluto: ofrece más control próximo al sistema que Java o Python, pero también proporciona abstracciones de alto nivel.

  3. Anotad dos ventajas y dos limitaciones de los niveles comparados. Relacionadlas con un contexto concreto, por ejemplo una aplicación web, el firmware de un sensor o una operación que tenga restricciones de recursos. No afirméis que un lenguaje de menor nivel es siempre más rápido o más adecuado.

4.4. Explorar estilos y paradigmas

  1. El grupo asignado a orientación a objetos guardará este ejemplo en Main.java y lo ejecutará con javac Main.java y java Main:

    class Coche {
        String marca;
        int velocidad = 0;
    
        void acelerar() {
            velocidad += 10;
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Coche miCoche = new Coche();
            miCoche.marca = "Toyota";
            miCoche.acelerar();
            System.out.println("Velocidad: " + miCoche.velocidad);
        }
    }
    

    Comprobad que la salida indica Velocidad: 10. Identificad la clase, el objeto, sus atributos y el método que cambia el estado.

  2. El grupo asignado al estilo funcional guardará y ejecutará este ejemplo en suma_funcional.py:

    def suma(a, b):
        return a + b
    
    
    resultado = suma(5, 7)
    print("El resultado es:", resultado)
    

    Comprobad que la salida es 12. Explicad por qué suma es una función pura en este ejemplo: sus entradas determinan el resultado y no modifica un estado externo. El uso de una función pura ilustra un estilo funcional, pero por sí solo no convierte a Python en un lenguaje exclusivamente funcional.

  3. Comparad ambos ejemplos y relacionadlos con los paradigmas de la teoría. Recordad que Java y Python son multiparadigma: la práctica compara dos estilos de organizar una solución, no dos categorías excluyentes de lenguajes.

4.5. Clasificar y elegir con criterios

  1. Elaborad una tabla para C, Python, Java, JavaScript y ensamblador. Incluid una fila por lenguaje y estas columnas: implementación o entorno considerado; modo de ejecución observado o habitual; nivel de abstracción relativo; paradigmas posibles; uso o contexto representativo. Escribid «depende de la implementación» cuando la etiqueta no sea absoluta y justificadlo.

  2. Elegid uno de estos escenarios y recomendad un lenguaje, indicando al menos dos razones y una limitación: firmware de un sensor con recursos limitados, aplicación web con interacción en el navegador o prototipo de análisis de datos. La respuesta debe apoyarse en requisitos, ecosistema y mantenimiento, no solo en popularidad.

4.6. Identificar prácticas generales de trabajo

  1. Revisad el proceso y anotad al menos cinco prácticas generales que también serían útiles en otra práctica, otro lenguaje o una herramienta distinta. Para cada una, indicad una evidencia de esta actividad y explicad qué error ayuda a evitar. Podéis considerar:

    • registrar sistema operativo, versiones y herramientas;
    • comparar el mismo problema pequeño para que las diferencias observadas sean atribuibles al lenguaje o al proceso, no a algoritmos distintos;
    • separar el código fuente de los archivos generados y recompilar después de modificarlo;
    • anotar los comandos y comprobar cada etapa antes de continuar;
    • leer el diagnóstico completo, corregir su causa y repetir la prueba;
    • contrastar el resultado con una predicción y conservar evidencias reproducibles;
    • describir las limitaciones de una clasificación y no generalizar a partir de una única herramienta.

    Estas son prácticas generales de trabajo, no una clasificación de lenguajes. Relacionadlas con las recomendaciones de la sección «Buenas prácticas» de la teoría 1.5.

5. Comprobaciones de finalización

  • Los programas del itinerario asignado se ejecutan y muestran la suma esperada, 12.
  • Has registrado versiones y herramientas y puedes describir qué ocurrió entre editar, compilar —cuando corresponda— y ejecutar.
  • La comparación distingue modo de ejecución, nivel de abstracción y paradigma como dimensiones diferentes.
  • La tabla no clasifica C como ensamblador ni describe Python, Java o JavaScript mediante una etiqueta absoluta sin mencionar el entorno pertinente.
  • Puedes explicar qué detalles oculta un lenguaje de alto nivel y qué control o complejidad añade el ensamblador.
  • Has identificado al menos cinco prácticas generales, cada una con una evidencia y una justificación.
  • El entregable contiene los fuentes, las respuestas y evidencias solicitadas.

6. Ejercicios y entregables

  1. 1.a. Ejecución y traducción: documenta la comparación de los dos lenguajes de tu itinerario.

    • 1.a.1. Incluye los comandos y las versiones utilizados.
    • 1.a.2. ¿Qué salida esperabas y cuál obtuviste?
    • 1.a.3. ¿Qué herramientas o entornos intervinieron antes y durante la ejecución?
    • 1.a.4. ¿En qué momento se detectarían los errores sintácticos que probaste? Distingue un error sintáctico de uno que aparezca durante la ejecución.
  2. 2.a. Abstracción: adjunta la tabla comparativa de Python o Java, C y ensamblador.

    • 2.a.1. Explica por qué «C es de bajo nivel» es una descripción relativa e incompleta.
  3. 3.a. Paradigmas: compara el objeto Coche y la función pura suma.

    • 3.a.1. Identifica dónde se conserva el estado en el ejemplo orientado a objetos.
    • 3.a.2. Explica qué cambia al calcular el resultado mediante una función que devuelve un valor.
  4. 4.a. Clasificación razonada:

    • 4.a.1. Completa la tabla solicitada en el paso 4.5.
    • 4.a.2. Recomienda un lenguaje para uno de los escenarios, indica al menos dos razones e incluye las limitaciones de tu recomendación.
  5. 5.a. Prácticas generales: presenta al menos cinco prácticas de trabajo transferibles, con la evidencia observada y el error que ayudan a prevenir.

  6. 6.a. Entrega: entrega un README.md identificado con tu nombre, módulo, unidad y práctica; incluye las respuestas, las tablas, las conclusiones, las versiones y los comandos. Añade los archivos fuente que hayas creado y una captura o transcripción de las salidas. Si una herramienta en línea oculta parte del proceso o no permite guardar un archivo generado, indícalo y aporta la evidencia disponible.

7. Solución orientativa

Los programas de suma deben mostrar 12. En C, GCC genera un ejecutable nativo para el entorno de destino; en CPython, el intérprete suele procesar bytecode; javac genera bytecode para la JVM, que puede interpretarlo o aplicar JIT; y los motores modernos de JavaScript pueden combinar interpretación y optimización JIT. Python, Java y JavaScript son lenguajes de alto nivel y multiparadigma; C ofrece más control próximo al sistema que Java o Python, pero no es ensamblador; el fragmento de ensamblador está ligado a una arquitectura. La salida de Coche es Velocidad: 10, y la función pura devuelve 12 sin modificar estado externo.

Fuentes y referencias