duduromeroa.com

RESEÑA: CAPÍTULO I

Programación orientada a objetos, una revisión histórica y técnica: primeras sintaxis de lenguajes de programación


Por Eduardo Romero | Guayaquil, Ecuador

www.duduromeroa.com, animación, lector, gif


#programación, #orientaciónObjetos, #sintaxis, #programación


Primero las máquinas, luego los humanos

Desde la década de 1960 la humanidad necesitó a usar sistemas de cómputo junto con lenguajes informáticos.

Pero en las primeras décadas de la computación los lenguajes informáticos requerían de un correcto descriframiento de signos algebráicos y palabras hiper simplificadas a tres caracteres. Eso era necesario para el sistema, pero poco agraciado para el humano que los manejaba.

Entre 1950 y 1970 lo que más importaba de los lenguajes de programación era su eficiencia. Las primeras sintaxis de programación eran elaboradas desde la utilidad de la máquina y no tanto para facilitar la comprensión de su operador humano.

Ese enfoque debía cambiar con urgencia. La principal razón es que un humano que crea código no siempre será el mismo quién lo releea, lo actualice o lo limpie. Aún hoy, con el uso de sistemas de Inteligencia Artificial (IA), el costo de no entender código escrito por otros (o por la IA) puede ser muy alto si se trata de actualizar o corregir errores importantes en un sistema de cómputo.

Hasta 1970 lo importante era la eficiencia de los lenguajes de programación y menos su comprensión por un operador humano.


La importancia de la legiblidad en el software

Fue desde el año 1987 cuando la industria de la computación consideró que mantener código era más importante que solo cuidar la eficiencia de los cálculos, debido a que construir, actualizar y "limpiar" software son tareas que generan más costos de tiempo y esfuerzo.

Para Sebesta (2012, p. 8) de entre las características que debe tener una sintaxis de lenguaje de programación que permita su correcto mantenimiento son:

  • La multiplicidad de características de un lenguaje de programación no debe impedir más de una forma de escribir una instrucción.
  • Debe evitar la sobrecarga de un operador (una palabra clave para ejecutar instrucciones). La sobrecarga será un problema cuando un mismo signo-operador tiene más de un contexto dentro de una sintaxis de lenguaje.
  • Debe tener un correcto equilibrio entre simplicidad y funcionalidad. Si un lenguaje es muy simple (con palabras-clave muy cortas) se corre el riesgo de que quién releea el código se pierda en los términos excesivamente abstractos.
  • Mantener una correcta ortogonalidad en la sintaxis de programación. Eso refiere a "un número menor de construcciones primitivas (básicas) y un conjunto consistente de reglas para combinarlas" (Sebesta, 2012, p. 16). Es decir, establece cuántas combinaciones de una cantidad manejable de sintaxis permiten construir complejidad. O en otras palabras, cuando una sintaxis permite comprender unas pocas reglas para aplicarlo en varias situaciones.
Ortogonalidad en sintaxis de programación

Lo ortogonal (cuando dos propiedades en L solo comparten el vértice, pero nunca se intersectan o se interrumpen) refiere a que una propiedad en la sintaxis del código no dependerá de otra propiedad. A más restricciones o condiciones, menos independencia (menos ortogonalidad). La ortogonalidad pregunta: ¿puedo combinar estas propiedades sin necesitar tantas reglas especiales?. Si es sí, entonces existe ortogonalidad (independencia entre propiedades).


Por ejemplo, a la pregunta de ¿En el lenguaje Javascript es válida una función con argumentos en forma de literales, pero sin valores explícitos? la respuesta es sí; ya que las funciones no necesitan valores en variables, una función puede recibir literales como valores ó valores explícitos en forma de argumentos.

Por lo tanto, el uso de variables y de valores explícitos en funciones de Javascript tienen un comportamiento ortogonal (cualquiera de las dos formas es de uso válido, no dependen de la otra).

En Javascript

// Argumentos en forma de literales
	function suma(a, b) {return a + b;}
	// Recién aquí se les asigna valores a cada uno
	console.log(suma(2, 3));
	// 7

// Argumentos en forma de valores explícitos
	function suma() {return 3 + 4;}
	console.log(suma());
	// 7

Abstracción de procesos

Los lenguajes de programación deben permitir abstracción tanto en procesos como en datos. La abstracción no evidencia cómo, dónde y con qué jerarquías se están trabajando los datos, pero sí permite operar con ellos. La abstracción oculta la complejidad de un proceso y muestra solo el resultado. Por ejemplo, en la ejecución de un algoritmo de clasificación, donde la sola ejecución reordena los elementos sin mostrar el proceso completo, reduciendo la obligación de comprender (y de revisar) todo lo involucrado.

También en la abstracción de sincronizaciones en un sistema (como ocurre con el framework React). Donde la coordinación de estados de elementos no es evidente para el desarrollador; este tan solo debe indicar qué elemento esta cambiando de estado.

Expresividad

Los lenguajes de programación deben permitir expresividad. Esto refiere a que una sintaxis debe contar con una forma más sencilla de indicar una operación. Como en la forma simplificada numero++ para expresar numero = numero + 1.

Confiabilidad

Los lenguajes de programación deben permitir la confiabilidad. Esto debe ocurrir cuando un lenguaje cuenta con eventos que alerten el uso incorrecto de la sintaxis o de las operaciones. Como en la evaluación de tipos de datos, donde se verifica que las operaciones del programa usen tipos de datos correctamente operables. Por ejemplo, un lenguaje no debería compilar variables (transformar código a bits comprensibles por un computador) que no contengan valores (aunque sí podría permitir escribirlo); o al intentar redeclarar valores constantes. Por ejemplo, JS me permite escribir:

En Javascript

const a = 10;
const a = 20; 

Pero al momento de compilarlo dará error (las constantes no se puede redeclarar), por lo tanto el programa no se ejecutará aunque el lenguaje sí me permitió escribir el código.

Dicho lo anterior, los primeros lenguajes de programación eran complejos de comprender y de mantener. Como veremos luego, enfoques como la orientación a objetos fueron creados para agilizar el aprendizaje pero también el pulido, la escala y el mantenimiento del código.

Primeras sintaxis de lenguajes de programación

La sintaxis de los primeros códigos máquina eran símiles de expresiones y de notación matemática/algebráicas, como en el lenguaje Short Code, de 1949, para computadores UNIVAC I (Sebesta, 2012, p. 40), el cual un interprete mecánico extremandamente lento ejecutaba las instrucciones. En la siguiente línea, el primer par de número refiere al identificador de las operaciones; luego, 'abs value' da el tipo de valor (uno absoluto); y la expresión final es la operación a ejecutar: la suma de n + 2 elevado a la potencia.

En ShortCode (1949) vs Javascript moderno

// En Short Code para Univac, de 1949
    01 - 06 abs value 1n (n+2)nd power

// En Javascript actual: 
    var x = 2;
    var y = 3;

    // Math.pow -> elevar a potencia indicada...
    // ...El primer valor -> Math.abs(x)
    // ...A la potencia de -> y
    var m = Math.pow(Math.abs(x), y);
    console.log(m);
    // 8

Luego, con el lenguaje ForTran (1952) y sus versiones (I, II, III IV, 77, 90, 95, y luego versiones 2003 y 2008), presentado como el primer lenguaje de conversión de instrucciones a código máquina (a compilado). Los nombres de variables que alojasen números enteros solo podian usar las letras I, J, K, L, M, N. Otros nombres con diferentes letras serían explícitamente de valores decimales.

En ForTran (se agregan comentarios para comprensión)

// ! Punto de entrada del programa; define el bloque principal
    program main

/* ! Obliga a declarar todas las variables explícitamente; evita errores silenciosos por nombres mal escritos */
  implicit none

 /* ! Arreglo de 99 enteros */
  integer, dimension(99) :: Int_List
  integer :: Longitud_lista, Contador, Suma, Promedio, Resultado

  Resultado = 0
  if ((Longitud_lista > 0) .and. (Longitud_lista < 100)) then
      do Contador = 1, Longitud_lista
          if (Int_List(Contador) > Promedio) then
              Resultado = Resultado + 1
          end if
      end do
  end if

// ! Finaliza el programa
end program main

Comparación con JS

let resultado = 0;
let longitud_lista = 3;
let int_list = [1,2,3];

for (let i = 0; i < longitud_lista; i++) {
    if (int_list[i] < 5) {
        console.log(resultado++);
    }
}
// 0 1 2

Si bien ForTran permitía crear listados de datos mediante arreglos, no eran listados dinámicos (es decir, un arreglo no podia ser alterado en tiempo real). Solo la versión de Procesamiento de lenguaje en lista Fortrar (1958) permitía ese manejo. Pero este no permitía expresiones condicionales. Recordemos que en la década de 1960 los computadores no contaban con suficiente memoria para que las nuevas versiones se explayen en nuevas características. Si añadían algo, se debía compensar quitando alguna funcionalidad anterior.

Décadas después, en 1958, el estudio de lenguajes de cómputo para simular inteligencia humana representó datos con símbolos, relaciones lógicas, expresiones y cálculo, todo para simular razonamiento. Todo eso debía ser acumulado en listas de datos (o en listas dentro de listas) para representar jerarquías, insertar, buscar o eliminar datos enlistados; o mejor aún, combinar dos o más listas en un complejo enlistado dinámico y actualizable de datos. El lenguaje LISP, creado en 1958 para las primeras investigaciones en Inteligencia Artificial fue creado para ese fin. Por ejemplo, para enlistar literales que representaban datos anidados en listas. En el ejemplo de abajo: el literal A corresponde a un dato del tipo átomo (un símbolo o un número como dato), (BC) es una sublista, D es otro átomo, y (E) es una lista que aloja una sublista (F G).

Lenguaje LISP (se agregan comentarios para comprensión)

(
    A
    (B C) 
        D 
        (E 
        (F G)
        )
)

// Y en otros casos, para definir una función
    // DEFUN        -> define un dato tipo función
    // equal_lists  -> nombra la función
    // lis1, lis2   -> nombres de argumentos 
    (DEFUN nombres_lists (lis1 lis2)

En esos años también se usó el lenguaje Algol (ALGOrithmic Language, 1958), creado por un comité de científicos alemanes y suizos para contrarestar la influencia de la empresa estadounidense IBM. Para mejorar la legibilidad, Algol introdujo bloques de código indicados con una palabra de inicio y otra de final del código. Antes de eso las sintaxis de programación no estaban agrupadas en secciones, sino más bien eran una lista interminable de instrucciones. También permitía indicar claramente desde dónde inicia un listado y dónde finaliza. Finalmente, se inserta un operador de asignación := para diferenciarlo de la igualdad '='.

Lenguaje Algol

begin
    integer array listadoNombres[1:99];
    integer sum;
    sum := 0
end

En resumen, en las sintaxis de muchos los lenguajes de programación antes y durante la década de 1960 bastaba con imitar los símbolos del álgebra y las matemáticas, o usar una cantidad muy limitada de literales para alojar valores y generar resultados. Pero esos atajos convertían un extenso código en algo inmanejable y con la obligación de invertir demasiado tiempo para escalarlo o corregirlo.

Debido a la necesidad de colaboración entre profesionales en pos de un constante mejoramiento del código (técnicamente conocido como depuración o debugging) fue necesario un nuevo modelo que permita crear y simular comportamientos más dinámicos, aleatorios y de fácil actualización de los estados (y comportamientos) de los datos contenidos en un sistema de cómputo.

Siguiente artículo: los paradigmas de programación acogen un moderno enfoque.


xxx texto que aparecerá al enviar el link por Whatsapp xxx


LIBROS CONSULTADOS
Sebesta, R., 2012. Concepts Of Programming Languages. Tenth Edition, Pearson.