Introducción al lenguaje Ada
Este capítulo tiene por objetivo mostrar los elementos escenciales del lenguaje de programación Ada. No se intenta ser completo ni preciso (exceptuando los ejemplos que si deben serlo). Principalmente la meta es lograr llegar al punto donde se pueda escribir programas útiles tan rápido como sea posible, concentrándose en las bases como variables y constantes, aritmética, control de flujo, funciones, procedimientos y herramientas de entrada y salida.
Estará fuera de alcance conceptos más avanzados, los cuales deben ser suplementados por la vasta información disponible en internet. Este apartado servirá tanto a programadores principantes como a los con experiencia, que podrían extrapolar sus conocimientos a los mencionados en este libro.
¿Por qué Ada frente a las alternativas?
Hoy en día existen multitud de lenguajes de programación. Se puede nombrar al venerable C y el moderno Rust como buenas opciones para crear aplicaciones a nivel del sistema operativo. Sin embargo existe Ada, con una historia tan venerable como C y con capacidades suficientes para ser utilizado en aplicaciones aeroespaciales, militares y de transporte, entre muchas otras.
Mantenibilidad y legibilidad
Si comparamos un programa de "Hola Mundo" entre los lenguajes Ada, C y Rust se puede ver que Ada es bastante fácil de leer por alguien no familiarizado en programación, en comparación con C y Rust que requieren un poco más de conocimientos previos para entender completamente lo que está pasando. El lenguaje Ada fue diseñado, entre otras cosas, para imprimirse en papel y ser lo más legible posible en cualquier punto del programa, sin generar dudas. Para que fuese comprensible al instante, sin necesidad de consultar el contexto.
with Ada.Text_IO;
procedure Hola is
begin
Ada.Text_IO.Put_Line("Hola, mundo desde Ada!");
end Hola;
#include <stdio.h>
int main(void) {
printf("Hola, mundo desde C!\n");
return 0;
}
fn main() {
println!("Hola, mundo desde Rust!");
}
En C, el código tiende a crecer en macros y punteros crípticos; en Rust, aunque moderno, su curva de aprendizaje enlaza con lifetimes y traits, que a veces complican la lectura de proyectos grandes.
Seguridad y confiabilidad
Ada incorpora un sistema de tipos muy estricto, detección de errores en tiempo de compilación y comprobaciones en tiempo de ejecución (como desbordamientos de enteros y accesos a arreglos). Esto reduce defectos críticos que en C suelen pasar inadvertidos hasta producción.
Concurrencia estructurada
Ada utiliza el concepto de "tareas" para la programación concurrente. Estas tareas son unidades de ejecución independientes que pueden correr concurrentemente con otras tareas dentro del mismo programa. La gestión de hilos o procesos a nivel del sistema operativo es diferente a la forma en que Ada maneja las tareas. Ada proporciona su propia abstracción para la concurrencia, lo que permite a los programadores escribir código concurrente sin tener que lidiar directamente con las complejidades del sistema operativo.
Ada fue de los primeros lenguajes en ofrecer mecanismos de concurrencia nativos:
-
Tareas (Tasks): hilos a nivel de lenguaje con comunicación via Rendezvous.
-
Objetos Protegidos (Protected Objects): acceso seguro a recursos compartidos sin miedo a condiciones de carrera.
-
Perfil de Ravenscar (Ravenscar Profile): un subconjunto definido para aplicaciones de tiempo real que garantiza determinismo y análisis de temporización.
Estos modelos superan la complejidad de hilos POSIX en C y evitan el sobrepeso de ecosistemas externos en Rust.
Certificaciones y estándares
Ada cumple con normas ISO (Ada 83, 95, 2005, 2012 y 2022). Existen perfiles y guías de certificación (DO-178C para aviación, IEC 61508 para seguridad funcional) que reconocen Ada como un lenguaje apto para sistemas críticos, ventaja que ni C ni Rust poseen de forma tan madura.
Retrocompatibilidad
Cada revisión de Ada mantiene compatibilidad con versiones anteriores, asegurando que bases de código de décadas sigan compilando sin cambios drásticos. Los compiladores (GNAT, AdaCore) ofrecen soporte industrial, análisis estático y herramientas de verificación (SPARK Ada) para auditorías formales.
Tabla Comparativa
La siguiente tabla resume las características y comparación entre Ada, C y Rust.
Característica | C | Rust | Ada |
---|---|---|---|
Tipado fuerte |
Débil |
Fuerte |
Muy fuerte, con chequeos en tiempo real. |
Concurrencia |
Hilos POSIX y sincronización |
async/await, threads |
Tasks, protected objects, Ravenscar |
Diseño por contrato |
No nativo |
Macros externas |
Integrado (Pre/Post/Invariant). |
Reglamento y certificación |
Parcial (MISRA C) |
Experimental |
Amplio (ISO, DO-178C, IEC 61508). |
Retrocompatibilidad |
Sí, pero con problemas de comportamiento no definido frecuentes. El mismo programa puede comportarse de forma distinta entre compiladores, o incluso cambiar de comportamiento al modificar una línea sin relación aparente. |
Al ser un lenguaje en evolución puede existir cambios que rompan código entre versiones. |
Sí, sin romper código existente. |
Ecosistema de herramientas |
Fragmentado |
Creciente |
Maduro (Alire, GNAT, SPARK, GNATcheck). |