Programación, lenguajes y paradigmas
|
Programación. La programación ha pasado por diferentes etapas históricas, en las que se fue evolucionando desde formas de programar directas en la computadora, hasta formas que están más cercanas del algoritmo de solución de los problemas. En los inicios, se empleó el propio lenguaje interno de la computadora (código de maquina), caracterizado por:
- Cada instrucción corresponde a una operación de maquina.
- El código de las operaciones así como los operandos se representan en binario.
Esta forma de programación en código de maquina resultó laboriosa y agobiante pues:
- El programa resulta excesivamente detallado.
- Contiene muchas especificaciones de maquina.
Una posibilidad de superar estas deficiencias es la representación simbólica (nemotécnica) de operandos y operadores, surgiendo los lenguajes orientados a maquina (que incluyen a ensambladores y macroensambladores), que aunque aligeran la comprensión y desarrollo de programas no elimina el grado de detalles de la programación ni la dependencia que tiene el programador de la máquina en específico.
Un paso superior es el uso de lenguajes que se adapten a las formas expresivas del ser humano y a la clase de problema a representar. Esto da lugar a la aparición de lenguajes de programación de alto nivel, que simplemente se conocen en la literatura actual como lenguajes de programación, en los cuales las estructuras de datos, operaciones y algoritmos son formulados de las formas que mejor convienen a la solución practica de problemas. Desde la aparición de los primeros lenguajes de programación hasta la actualidad se ha producido una evolución constante en los mismos, observándose dos tendencias fundamentales en tal desarrollo:
- Una gran diversificación de lenguajes especiales representados por sistemas de programación que cubren una gama de problemas específicos (por ejemplo, lenguajes para el procesamiento gráfico, para manipulación de fórmulas, etc.) A tales lenguajes y sistemas se les llama lenguajes de programación orientados a problemas, como "FORTRAN", "COBOL".
Una integración sobre la base de la generalización de los conceptos más generales de la programación y una amplia gama de aplicaciones son los lenguajes de programación universales, como ALGOL, PL/1, Pascal, etc.
Ya desde los primeros tiempos del desarrollo de las técnicas de computación se realizaron intentos de desarrollar lenguajes de programación de alto nivel. En 1954 Backus desarrolla la concepción general del lenguaje de programación FORTRAN, a partir de lo cual se desarrolla vertiginosamente los lenguajes de programación.
Sumario
- 1 Desarrollo de los primeros lenguajes
- 2 Utilidad del estudio de los lenguajes de programación
- 3 Aspectos a tener en cuenta al escoger un lenguaje de programación
- 4 Adecuación al problema a resolver
- 5 Claridad, sencillez y unidad
- 6 Facilidades de aplicación.
- 7 Recursos para la abstracción
- 8 Facilidad para verificar programas
- 9 Entorno de programación
- 10 Portabilidad de programas
- 11 Ortogonalidad
- 12 Generalidad
- 13 Uniformidad
- 14 Eficiencia
- 15 Eficiencia en la traducción.
- 16 Implementabilidad
- 17 Eficiente en la programación
- 18 Costo de uso
- 19 Sintaxis, semántica y pragmática de un lenguajes de programación
- 20 Compilación e interpretación
- 21 Lo estático y lo dinámico en un lenguaje de programación
- 22 Paradigmas computacionales
- 23 Paradigma imperativo
- 24 Paradigma funcional
- 25 Paradigma de la programación lógica
- 26 Programación Orientada a Objetos
- 27 Lenguajes relacionados
- 28 Bibliografía
Desarrollo de los primeros lenguajes
A continuación se sintetiza en forma breve el desarrollo de lenguajes durante los primeros días de la computación, en general desde mediados de los años cincuenta hasta principios de los setenta.
Lenguajes basados en el cálculo numérico
Las primeras máquinas estaban proyectadas para resolver problemas numéricos y se pensaba en ellas como en calculadoras electrónicas, por lo que los cálculos numéricos fueron la forma dominante de aplicación para estas máquinas iniciales.
De 1955 a 1957 John Backus encabezó el equipo para desarrollar Fortran, o FORmula TRANslator. Fortran se orientaba en torno a cálculos numéricos, pero la meta era un lenguaje de programación que incluyera estructuras de control, condicionales y enunciados de entrada y de salida.
Fortran tuvo un éxito extraordinario, tanto así que cambió para siempre la programación. Se hizo una revisión de Fortran en 1958 (Fortran II) y otra más unos años después (Fortran IV). En 1966, Fortran IV se convirtió en estándar con el nombre de Fortran 66 y ha sido actualizado dos veces desde entonces, a Fortran 77 y Fortran 90. Sin embargo, el número extremadamente grande de programas escritos en estos primeros dialectos ha sido causa de que las generaciones subsiguientes de traductores sean casi todas compatibles con estos antiguos programas e inhibe el uso de características modernas de programación.
A causa del éxito de Fortran, existía el temor, en especial en Europa, de que IBM dominara la industria. La GAMM (la Sociedad Alemana de Matemáticas Aplicadas) organizó un comité para diseñar un lenguaje universal. En Estados Unidos, la Association for Computing Machinery (ACM; asociación para maquinaria de cómputo) también organizó un comité similar. Aunque inicialmente los europeos temían ser dominados por los estadounidenses, los comités se fusionaron. Bajo el liderazgo de Peter Naur, el comité desarrolló el International Algorithmic Language (IAL; lenguaje algorítmico internacional). Aunque se propuso ALGOrithmic Language (ALGOL; lenguaje algorítmico), el nombre no fue aprobado. Sin embargo, el uso común obligó a cambiar el nombre oficial y el lenguaje se conoció como ALGOL
Una revisión tuvo lugar en 1960 y el ALGOL 60 (con una revisión menor en 1962) se convirtió en el lenguaje "académico" de cómputo estándar desde los años sesenta hasta principios de los setenta.
En tanto que una meta para el Fortran era la eficiencia en la IBM 704, ALGOL]] tenía objetivos muy distintos:
- La notación de ALGOL debería aproximarse a las matemáticas normales.
- ALGOL debería ser útil para la descripción de algoritmos.
- Los programas en ALGOL deberían ser compilables a lenguaje de máquina.
- ALGOL no debería estar ligado a una sola arquitectura de computadora. Éstos resultaron ser objetivos muy ambiciosos para 1957. Para dar cabida a la independencia de las máquinas, no se incluyó entrada ni salida en el lenguaje; se podían escribir procedimientos especiales para estas operaciones.
ALGOL nunca alcanzó éxito comercial en Estados Unidos, aunque consiguió cierto éxito en Europa. Sin embargo, tuvo un impacto más allá de su uso, por la trascendencia y valor de los conceptos de programación que incorporó. Backus fue el editor del informe de ALGOL que definía el lenguaje Usó una notación sintáctica basada en una gramática libre de contexto desarrollado por Chomsky. Esto constituyó la introducción de la teoría formal de las gramáticas al mundo de los lenguajes de programación. Esta notación se conoce ahora como BNF, o Backus Naur Form (forma de Backus Naur).
El concepto de tipos definidos por el usuario se desarrolló en los años sesenta. Ni FORTRAN ni ALGOL disponían de esta característica.Simula-67, desarrollado por Nygaard y Dahl de Noruega, introdujo el concepto de clases en ALGOL. Esto le proporcionó a Stroustrup la idea para sus clases de C++, como una extensión de C más tarde en los años ochenta. Wirth desarrolló ALGOL-W a mediados de la década de 1960 como una extensión de ALGOL. Este diseño tuvo sólo éxito menor; sin embargo, entre 1968 y 1970 Wirth desarrolló Pascal, el cual se convirtió en el lenguaje de la ciencia de la computación en los años setenta. Otro comité intentó repetir el éxito de ALGOL 60 con ALGOL 68, pero el lenguaje era radicalmente distinto y demasiado complejo para que la mayoría lo pudiera entender o implementar de manera eficaz.
Con la introducción de su nueva línea de computadoras 360 en 1963, la IBM desarrolló NPL (New Programming Language; nuevo lenguaje de programación) en su Laboratorio Hursley en Inglaterra. Después se acortó a sólo PL/I. El PL/I fusionó los atributos numéricos de FORTRAN con las características de programación para negocios de COBOL. PL/I alcanzó un éxito moderado en los años setenta, pero su uso actual está disminuyendo al ser reemplazado por C y Ada.
Por último, el BASIC se desarrolló para satisfacer las necesidades de cálculo numérico del no científico, pero se ha extendido mucho más allá de su meta original.
Lenguajes para negocios
El procesamiento de datos de negocios era uno de los primeros dominios de aplicación por desarrollar después de los cálculos numéricos. En 1959, el Departamento de Defensa de Estados Unidos. patrocinó una reunión para desarrollar el Common Business Language (CBL; lenguaje común para negocios), el cual habría de ser un lenguaje orientado a negocios. Para 1960 ya se tiene el COBOL (COmnmon Business Oriented Language; lenguaje común orientado a negocios). COBOL fue revisado en 1961 y 1962, estandarizado en 1968 y revisado una vez más en 1974 y 1978.
Lenguajes para inteligencia artificial.
John McCarthy, del MIT, diseñó en la década de los 50 el lenguaje LISP (LIST Processing; procesamiento de listas) para la IBM 704. Más recientemente, Scheme y Common LISP y otros han continuado esa evolución. LISP fue proyectado como un lenguaje funcional para procesamiento de listas. El dominio ordinario de problemas para LISP comprendía la búsqueda. En tanto que LISP fue proyectado para aplicaciones de procesamiento de listas para usos generales, Prolog fue un lenguaje para usos especiales, cuya estructura básica, el control y su estrategia de implementación se basaban en conceptos de lógica matemática.
Lenguajes para sistemas
A causa de la necesidad de eficiencia, el uso de lenguaje ensamblador se mantuvo durante años en el área de sistemas, incluso tiempo después de que otros dominios de aplicación comenzaron a emplear lenguajes de mayor nivel. Se diseñaron algunos lenguajes que nunca tuvieron amplia aceptación, hasta que apareció el lenguaje C. Con el desarrollo del sistema operativo UNIX escrito en C durante los primeros años de la década de 1970, se demostró la eficacia de lenguajes de alto nivel en este entorno.
Utilidad del estudio de los lenguajes de programación
El estudio de un lenguaje de programación debe enfilarse a:
- Conceptos y estructuras fundamentales de los lenguajes.
- Principios de su funcionamiento.
- Representación de sus conceptos y constructores en la computadora
Esto resulta conveniente pues:
- Mejora la comprensión del lenguaje concreto que se está tratando.
- Aumenta el caudal de recursos útiles de programación.
- Facilita la selección del lenguaje conveniente para resolver un problema.
- Facilita la asimilación de un nuevo lenguaje.
- Facilita la elaboración de un nuevo lenguaje.
Entre los propósitos de un lenguaje de programación debe estar el de servir de:
- Herramienta de diseño
- El lenguaje debe ayudar a escribir buenos programas (facilidades de leer, entender y modificar).
- Vehículo de comunicación de las personas
Cuando el programa necesite ser utilizado o modificado o se acomete un proyecto de programación entre varias personas. Entonces es mas importante poder leer y comprender que hace el programa que escribirlo.
- Vehículo de comunicación con la computadora.
El programa debe ser ejecutado en la computadora, para en ultima instancia medir la validez del mismo, en espacio razonable y tiempo prudencial. Resultan necesarios conocimientos de cómo de instrumenta el lenguaje y del valor de los recursos que usa el programa y debe lograrse un balance adecuado entre eficiencia y generalidad.
Aspectos a tener en cuenta al escoger un lenguaje de programación
Algunas de las razones del éxito o fracaso de un lenguaje pueden ser externas al lenguaje mismo. Por ejemplo, el uso de COBOL o Ada en Estados Unidos se impuso en ciertas áreas de programación por mandato del gobierno. De manera similar, parte de las razones del éxito del FORTRAN pueden atribuirse al fuerte apoyo de diversos fabricantes de computadoras que han invertido grandes esfuerzos para proveer implementaciones refinadas y una documentación extensa para estos lenguajes.
Parte del éxito de SNOBOL4 durante los años setenta se puede atribuir a un texto excelente que describe el lenguaje [GRISWOLD 1975]. Pascal y LISP se han visto beneficiados por su uso como objetos de estudio teórico por parte de estudiantes de diseño de lenguajes, así como por su empleo práctico efectivo.
A pesar de la gran importancia de algunas de estas influencias externas, es el programador quien determina en último término, aunque a veces de manera indirecta, cuáles lenguajes viven o mueren. Se podrían sugerir múltiples razones para explicar por qué los programadores prefieren un lenguaje respecto a otro. En general los aspectos pueden ser:
(a)Adecuación al tipo de problema a resolver. (b)Facilidades de extensión, ejemplo, subrutinas, procedimientos, módulos, abstracción de datos. (c)Sencillez, simplicidad, consistencia, tanto sintáctica como semánticamente. (d)Aseguramiento externo. (e)Editores de texto, debugger, facilidades de utilización de bibliotecas, buena documentación del lenguaje. (f)Cantidad de recursos de la computadora, en tiempo y espacio. (g)Grado de generalidad, ortogonalidad y uniformidad. (h)Eficiencia.
Consideremos algunas de ellas.
Adecuación al problema a resolver
Una de las primeras cosas que son evaluadas al escoger un lenguaje son las características propias del problema a resolver. Así, si debemos enfrentar el desarrollo de una aplicación de inteligencia artificial, por ejemplo, desarrollar un sistema experto, la primera idea que nos viene es usar un lenguaje funcional o de programación lógica, como LISP o Prolog; si deseamos desarrollar un programa de sistema, pensaríamos en C, si deseamos desarrollar una aplicación de programación por Internet, la primera mirada iría al Java. Si bien este criterio no es determinante, pues incluso podríamos escoger de entre varios lenguajes para desarrollar una aplicación, es de un peso considerable.
Claridad, sencillez y unidad
Un lenguaje de programación proporciona a la vez un marco conceptual para pensar acerca de los algoritmos y un medio de expresar esos algoritmos. El lenguaje debe constituir una ayuda para el programador incluso antes de la etapa misma de codificación. Debe proveer un conjunto claro, sencillo y unificado de conceptos que se puedan usar como primitivas en el desarrollo de algoritmos. Para ello, es deseable contar con un número mínimo de conceptos distintos cuyas reglas de combinación sean tan sencillas y regulares como sea posible. Llamaremos a este atributo integridad conceptual.
La sintaxis de un lenguaje afecta la facilidad con la que un programa se puede escribir, poner a prueba, y más tarde entender y modificar. La legibilidad de los programas en un lenguaje es aquí una cuestión. Una sintaxis que es rigurosa o hermética suele facilitar la escritura de un programa (para el programador con experiencia) pero dificulta su lectura cuando es necesario modificarlo más tarde. Los programas en APL suelen ser tan herméticos que sus propios diseñadores no pueden descifrarlos pocos meses después de haberlos completado.
Muchos lenguajes contienen construcciones sintácticas que favorecen una lectura errónea al hacer que dos enunciados casi idénticos signifiquen cosas radicalmente distintas. Por ejemplo. la presencia de un carácter en blanco, que es un operador, en un enunciado en SNOBOL4 alterar por completo su significado. Un lenguaje debe tener la propiedad de que las construcciones que signifiquen cosas distintas se vean diferentes; es decir, las diferencias semánticas deberán reflejarse en la sintaxis del lenguaje.
Facilidades de aplicación.
Un lenguaje necesita una sintaxis que, al usarse correctamente, permita que la estructura del programa refleje la estructura lógica del algoritmo. Idealmente deberá ser posible traducir directamente un diseño a enunciados de programa adecuados que reflejen la estructura del algoritmo. Los algoritmos secuenciales, algoritmos concurrentes, algoritmos lógicos, etc., todos ellos tienen estructuras naturales diferentes que están representadas por programas en esos lenguajes. El lenguaje deberá suministrar estructuras de datos, operaciones, estructuras de control y una sintaxis natural apropiada para el problema que se va a resolver. Una de las razones principales de la proliferación de lenguajes es precisamente esta necesidad de naturalidad. Un lenguaje particularmente adecuado para una cierta clase de aplicaciones puede simplificar grandemente la creación de programas en esa área. Prolog, con su inclinación hacia propiedades deductivas, y C++, para diseño orientado a objetos, son dos lenguajes con una inclinación obvia a clases particulares de aplicaciones.
Recursos para la abstracción
Incluso con una tendencia de programación más natural para una aplicación, siempre queda una brecha considerable entre las estructuras de datos y operaciones abstractas que caracterizan la solución de un problema y las estructuras de datos primitivas y operaciones particulares integradas en un lenguaje. Por ejemplo, C puede ser un lenguaje apropiado para construir un programa para organizar los horarios de clases en una universidad, pero las estructuras de datos abstractos de "estudiante", "sección de clase", "instructor", "salón de clases" y las operaciones abstractas de "asignar un estudiante a una sección de clase", etc., que son naturales para la aplicación, no son suministradas directamente por C.
Una parte considerable de la tarea del programador es proyectar las abstracciones adecuadas para la solución del problema y luego implementar esas abstracciones empleando las capacidades más primitivas que provee el lenguaje de programación mismo. Idealmente, el lenguaje debe permitir la definición y el mantenimiento de las estructuras de datos, de los tipos de datos y de las operaciones como abstracciones autosuficientes. El programador puede emplear todo esto en otras partes del programa conociendo sólo sus propiedades abstractas, sin preocuparse por los detalles de su implementación. Tanto Ada, C++, Object Pascal, [[Eiffel, Java y otros se desarrollaron debido precisamente a estos defectos de los lenguajes más antiguos Pascal y C, respectivamente.
Facilidad para verificar programas
La corrección de los programas escritos en un lenguaje es siempre una preocupación medular. Existen muchas técnicas para verificar que un programa ejecuta correctamente la función requerida. Se puede probar que un programa es correcto a través de un método formal de verificación, se puede probar informalmente que es correcto por verificación de escritorio (leer y verificar visualmente el texto del programa), se puede poner a pruebaejecutándolo con los datos de entrada de prueba y comparando los resultados de salida con las especificaciones, etc. Para programas grandes se suele emplear alguna combinación de todos estos métodos. El uso de un programa que dificulta la verificación de programas puede ser mucho más problemático que el de uno que apoya y simplifica la verificación, no obstante que el primero pueda proporcionar muchas capacidades que superficialmente parecen hacer más fácil la programación. La sencillez de la estructura semántica y sintáctica es un aspecto primordial que tiende a simplificar la verificación de programas.
Entorno de programación
La estructura técnica de un lenguaje de programación es sólo uno de los aspectos que afectan su utilidad. La presencia de un ambiente de programación adecuado puede facilitar el trabajo con un lenguaje técnicamente débil en comparación con un lenguaje más fuerte con poco apoyo externo. Se podría incluir una larga lista de factores como parte del entorno de programación. La disponibilidad de una implementación confiable, eficiente y bien documentada del lenguaje debe encabezar la lista. Los editores especiales y paquetes de prueba hechos para el lenguaje pueden acelerar mucho la creación y puesta a prueba de programas. Los recursos para el mantenimiento y modificación de múltiples versiones de un programa pueden simplificar mucho el trabajo con programas grandes. Smalltalk fue proyectado específicamente alrededor de un entorno de programación compuesto de ventanas, menús, uso del ratón y un conjunto de herramientas para operar sobre programas escritos en Smalltalk. Otros lenguajes se han desarrollado en versiones actuales con poderosos medios de edición y desarrollo de aplicaciones, como ambientes RAD (rapid application development), de los cuales las herramientas visuales que soportan al Pascal o C++ (Delphi, C++ Builder, Visual Basic) son sólo una muestra.
Portabilidad de programas
Un criterio importante para muchos proyectos de programación es el de la portabilidad de los programas resultantes de la computadora en la cual se desarrollaron hacia otros sistemas de computadoras. Un lenguaje que está ampliamente disponible y cuya definición es independiente de las características de una máquina particular constituye una base útil para la producción de programas transportables. Ada, FORTRAN, C y Pascal tienen todos ellos definiciones estandarizadas que permiten la implementación de aplicaciones transportables. Otros, como ML provienen de una implementación de fuente única que permite al diseñador de lenguaje cierto control sobre las características transportabas del lenguaje.
Ortogonalidad
Se refiere a la capacidad de combinar varias características de un lenguaje en todas las combinaciones posibles, de manera que todas ellas tengan significado. Por ejemplo, supóngase que un lenguaje dispone de una expresión que puede producir un valor y también dispone de un enunciado condicional que evalúa una expresión para obtener un valor de verdadero o falso. Estas dos características del lenguaje, la expresión y el enunciado condicional, son ortogonales si se puede usar (y evaluar) cualquier expresión dentro del enunciado condicional.
Cuando las características de un lenguaje son ortogonales, entonces es más fácil aprender el lenguaje y escribir los programas porque hay menos excepciones y casos especiales que recordar. El aspecto negativo de la ortogonalidad es que un programa suele compilar sin errores a pesar de contener una combinación de características que son lógicamente incoherentes o cuya ejecución es en extremo ineficiente. A causa de estas cualidades negativas, la ortogonalidad como atributo de un diseño de lenguaje es todavía motivo de controversia, pues a ciertas personas les gusta y a otras no.
La no generalidad de la comparación de igualdad puede ser vista como una no ortogonalidad ya que la aplicación de “=” depende del tipo de los valores a comparar. Otros ejemplos adicionales de pérdida de ortogonalidad:
- Las funciones Pascal pueden retomar sólo valores escalares o apuntadores.
- En C valores de todo tipo, excepto de tipo arreglo, pueden ser retomados desde una función.
- En Ada esta no-ortogonalidad se elimina.
- En Pascal los tipos ficheros tienen un status especial que causa un número de no-ortogonalidades, por ejemplo, los ficheros no pueden ser pasados por valor y esta prohibida la asignación a variables fichero. En muchos otros lenguajes los ficheros forman parte de bibliotecas (dependientes del sistema) en vez de a la definición del lenguaje evitando con ello tales no-ortogonalidades.
- En Modula 2 las cadenas pueden asignarse a variables de cadena de mayor longitud, pero no viceversa, este es el único caso en Modula 2 donde la asignación trabaja para objetos de igual medida.
- En C hay una no ortogonalidad en el traspaso de parámetros: C pasa todos los parámetros por valor excepto los arreglos que los pasa por referencia. Aquí se ve mejor la no ortogonalidad.
La ortogonalidad fue la meta principal del ALGOL-68, que sigue siendo el mejor ejemplo de lenguaje donde sus constructores pueden ser combinados en todas maneras significativas.
Generalidad
Se alcanza evitando casos especiales en cuando a disponibilidad o uso de constructores y por la combinación de constructores muy relacionados en uno mas general. La no generalidad esta ligada a restricciones de los constructores con independencia del contexto en que estén.
Ejemplos que indican perdida de generalidad
- Pascal posee declaraciones de procedimientos y parámetros por valor en los procedimientos, pero en sus versiones originales no poseía variables procedimentales. Por ello la definición de procedimiento en Pascal perdía
generalidad. Esta restricción se elimina en Modula 2, así como en Object Pascal, pero se mantiene en Ada (donde no existen parámetros procedimientos)
- Pascal no posee arreglos de longitud variable, por ello arreglos pierde generalidad. C y Ada poseen arreglos de longitud variable y Modula 2 y FORTRAN tienen la habilidad de pasar parámetros arreglo de longitud variable,
pero no pueden definir tipos de arreglo de longitud variable.
- En Pascal y Modula 2 el operador “=” puede ser aplicado a escalares, punteros o conjunto, pero no a arreglos. Por ello “=” pierde generalidad. Una restricción similar se aplica en C.
- FORTRAN sólo posee traspaso por referencia, ALGOL 68 sólo por valor pero alcanza generalidad permitiendo un puntero a cualquier objeto para ser pasado por valor. FORTRAN no posee tal facilidad.
- FORTRAN no posee constantes nombradas. En Pascal no se permite una constante ser expresión, mientras en Modula-2 expresiones constantes no pueden incluir llamados de función. Ada tiene una facilidad de declaración de
constantes completamente general (las constantes pueden ser controladores dinámicos).
La generalidad puede ser un principio peligroso que puede afectar a otros principios, por ejemplo, reduce la simplicidad de un lenguaje y lo puede hacer menos legible y confiable. Por ejemplo, en Pascal se restringen los apuntadores para evitar inseguridades, pero en C se les permite ser mucho más generales bajo mayores riesgos de programación.
Uniformidad
Este principio centra su atención en la consistencia de la apariencia y del comportamiento de los constructores del lenguaje. Las no-uniformidades son de dos tipos:
- dos cosas similares que no son vistas o no se comportan similarmente, o
- cosas no similares que son vistas o se comportan similarmente cuando no debieran.
Ejemplos de no uniformidad
- En Pascal la instrucción repeat abre sus propios bloques de instrucciones, pero la instrucción while y la condicional if requieren pares begin – end .
- Modula-2 y Ada rectifican esta no-uniformidad.
- El enunciado case en registros variantes en Pascal tiene una sintaxis diferente del case como estructura de control.
Esta situación se rectifica con el Modula-2. *Los valores retornados por funciones en Pascal aparecen como asignaciones
Ejemplo function f: boolean
begin ... f:= true
end
La mayoría de los lenguajes usan instrucciones return para esto. No-uniformidades pueden ser vistas en algunos casos como no ortogonalidades también, ya que no-uniformidades ocurren en contextos particulares y pueden ser vistos como interacciones entre constructores.
Eficiencia
Se expresa a través de: 1.Código ejecutable eficiente. Podemos ejemplificar la posibilidad de variables con chequeo estático de tipos. Las constantes en Pascal están restringidas a valores explícitos, por lo que los identificadores de constantes pueden ser remplazados por sus valores durante la traducción, haciendo el código generado más corto y rápido.
Eficiencia en la traducción.
¿Permite el diseño del lenguaje escribir un compilador de una pasada? Este es el caso de Pascal donde las variables deben ser declaradas antes de usarse. En Modula 2 el compilador requiere una segunda pasada para resolver referencias de identificadores.
Implementabilidad
Se refiere a la eficiencia con la cual puede ser escrito un compilador. Esto está relacionado con eficiencia de traducción, pero está en función de la complejidad de la definición del lenguaje. El éxito de un lenguaje puede decaer simplemente porque es muy difícil escribir un traductor o porque los algoritmos que realizan la traducción no son suficientemente bien comprendidos. Una de las razones por las que ALGOL-6O no fue más usado en USA puede haber sido que las estructuras basadas en pilas necesitadas por el sistema en tiempo de ejecución no eran ampliamente conocidas en esos tiempos. El tamaño y complejidad del Ada ha sido un escollo al desarrollo de compiladores y ha disminuido su disponibilidad y uso.
Eficiente en la programación
¿Cuán rápida y fácilmente pueden escribirse programas en el lenguaje? Una cualidad que se tiene en cuenta aquí es la expresividad del lenguaje: ¿cuán fácil es expresar procesos y estructuras complejas? Esto está relacionado al poder y generalidad del mecanismo de abstracción del lenguaje. Una sintaxis concisa y la evitación de detalles innecesarios, tales como declaraciones de variables, se considera a menudo como características importantes de esta clase de eficiencia. Desde este punto de vista LISP y Prolog son ideales por su sintaxis concisa, ausencia de declaraciones y muchos detalles de los cálculos pueden dejarse al sistema de tiempo de corrida. Esto, por supuesto, compromete otros principios del lenguaje como legibilidad, eficiencia de ejecución y confiabilidad.
Costo de uso
Se ha dejado para el final el criterio del costo. Es indudable que el costo es un elemento importante en la evaluación de cualquier lenguaje de programación, pero son factibles diferentes medidas del mismo:
Costo de ejecución del programa
En los primeros días de la computación, la cuestiones de costo se referían casi exclusivamente a la ejecución de los programas Era importante el diseño de compiladores que optimizaban la asignación eficiente de registros y el diseño de mecanismos eficientes de apoyo al tiempo de ejecución. El costo de ejecución del programa, aunque siempre ha tenido cierta importancia en el diseño de lenguajes, es de importancia primordial para grandes programas de producción que se van a ejecutar con frecuencia. En la actualidad, sin embargo, para muchas aplicaciones la velocidad de ejecución no es la preocupación mayor. Con computadoras que trabajan a varios millones de instrucciones por segundo y que están ociosas gran parte del tiempo, se puede tolerar un incremento de 10% a un 20% del tiempo de ejecución si ello significa un mejor diagnóstico o un control más fácil por parte de usuario sobre el desarrollo y mantenimiento del programa.
Costo de traducción de programas
Cuando un lenguaje como FORTRAN o C se utiliza en la enseñanza, la cuestión de una traducción (compilación) eficiente, o la ejecución eficiente, puede ser de importancia capital. Típicamente, los programa estudiantiles se compilan muchas veces cuando se están depurando pero se ejecuta sólo unas pocas veces.
En casos así, es importante contar con un compilador rápido eficiente en vez de un compilador que produzca un código ejecutable optimizado.
Costo de creación, prueba y uso de programas.
Un tercer aspecto del costo de un lenguaje de programación queda ejemplificado por el lenguaje SmallTalk., Para un cierta clase de problemas se puede diseñar, codificar, probar, modificar y usar una solución con una inversión mínima en tiempo y energía del programador. SmallTalk es económico en cuanto a que se minimizan el tiempo y esfuerzo totales que se invierte en la solución de un problema en la computadora. La preocupación por esta clase de costo de conjunto en el uso de un lenguaje se ha vuelto tan importante en muchos casos como la inquietud por la ejecución y compilación eficiente de los programas.
Costo de mantenimiento de los programas
Muchos estudios han demostrado que el costo más grande que interviene en cualquier programa que se utiliza a lo largo de un periodo de años no es el costo del diseño, codificación y prueba inicial del programa sino los costos totales del ciclo de vida, que incluyen los costos de desarrollo y el costo de mantenimiento del programa en tanto continúa en uso productivo. El mantenimiento incluye la reparación de errores, los que se descubren después de que se comienza usar el programa, cambios que requiere el programa cuando se actualiza el hardware subyacente o el sistema operativo, y extensiones y mejoras al programa que se requiere.
Sintaxis, semántica y pragmática de un lenguajes de programación
En términos lingüísticos un lenguaje es un conjunto de secuencias de símbolos que constituyen frases del lenguaje, las que se construyen a partir de cierto conjunto de símbolos (alfabeto) sujetas a ciertas reglas de construcción. La sintaxis explica la estructura de las frases del lenguaje. Ella ofrece cuáles cadenas de símbolos sobre un alfabeto constituyen frases validas del lenguaje. La semántica asigna significado a cada frase sintácticamente admisible en el lenguaje, expresando como se transforman cuando son ejecutadas.
Las propiedades sintácticas de un lenguaje de programación se refieren a las propiedades estructurales inherentes a las estructuras de información del lenguaje, en tanto la semántica se refiere a las propiedades transformacionales de la estructura.
Es conveniente tener una notación para especificar las propiedades sintácticas y semánticas de las estructuras de un lenguaje de programación. La notación sintáctica de un lenguaje de programación especifica la clase de programas que se pueden escribir en el lenguaje de programación. La notación semántica de un lenguaje de programación especifica el efecto de ejecución de todos los programas en ese lenguaje de programación.
Notaciones sintácticas formales:
- BNF
- Diagramas sintácticos
Notaciones semánticas formales.
- Semántica operacional
- Semántica denotacional
- Semántica axiomática
Compilación e interpretación
La compilación consiste en la traducción de un programa escrito en un lenguaje de programación de alto nivel en su equivalente en código de maquina (programa objeto). Ninguna porción del programa objeto es ejecutada hasta tanto no se haya traducido todo el programa fuente.
El intérprete no produce como salida un programa objeto, sino que proceda el programa fuente instrucción a instrucción. Una instrucción en el programa fuente es tomada por el intérprete; ella es interpretada para determinar que operaciones desean ser realizadas por el usuario y las mismas son ejecutadas. Solo una vez que una instrucción es completamente interpretada y ejecutada se pasa a la siguiente
Lo estático y lo dinámico en un lenguaje de programación
Lo estático es lo que se mantiene invariable durante la ejecución de los programas en un lenguaje de programación. Las propiedades sintácticas son de hecho estáticas. Lo dinámico es todo aquel concepto que puede sufrir variaciones en tiempo de ejecución. Por ejemplo, la semántica puede tener propiedades estáticas y dinámicas. Lo estático en la semántica se refiere a aquellas propiedades del lenguaje no comprendidas en la sintaxis y que pueden ser controladas durante la traducción del programa.
Ejemplos
- El tamaño de las declaraciones de un bloque en Pascal.
- Chequeo de tipos: todas las variables son declaradas.
Lo dinámico en la semántica se refiere a aquellas propiedades que describen la interpretación de las frases significativas del lenguaje y tales elementos del lenguaje pueden realizarse con la ejecución de una maquina abstracta, una vez traducido el programa, ejemplos, los cambios de valores de las variables, asignación de memoria a variables cuando se va a ejecutar un bloque (Pascal).
Paradigmas computacionales
Los paradigmas de programación son modelos que describen cómo diseñar e implementar programas. Diferentes paradigmas dan lugar a diferentes técnicas de programación, lo cual no implica que ellos sean contradictorios, sino que más bien unos tienden a complementar otros, por lo que la programación actual tiende a ser multiparadigma. Los paradigmas se asemejan en que se apoyan en un diseño basado en abstracciones que corresponden a elementos en el problema de programación y que la implementación debe ser una colección de módulos preferentemente reutilizables.
Ellos difieren el cómo formar esas abstracciones y en la forma de componer el programa a partir de una colección de funciones. Las técnicas de programación brindan una guía de cómo diseñar, organizar e implementar las funciones de las que se compone el programa. Ejemplo de estas técnicas son:
- Descomposición funcional, que identifica las funciones que sirven como operaciones abstractas del problema.
- Abstracción de datos, que permite diferir las estructuras de datos representativas de las entidades presentes en el problema y las operaciones que se realizan con ellas.
- Encapsulamiento, que facilitan reunir estructuras de datos y operaciones en un tipo abstracto, dando sólo forma de acceso a la estructura a través de sus operaciones.
- Organización de ficheros, que permite formar biblioteca de código reutilizable.
Paradigma imperativo
Caracterizado por:
- Ejecución secuencial de las instrucciones.
- Uso de variables para representar localizaciones de memoria.
- Uso de asignación para cambiar el valor de las variables muchas veces son llamadas procedurales.
Que se recoge también en la siguiente definición: “Un lenguaje de programación es Turing-completo si posee variables enteras, aritmética entera y ejecuta instrucciones secuencialmente, las que incluyen asignación, selección y ciclo (while)”.
Ejemplo Sea el cálculo imperativo del máximo común divisor.
procedure gcd (u,v: integer; var x : integer); var y, t: integer ; begin x:= u ; y:= v ; while y > 0 do begin t:= y ; y:= x mod y; x:= t end end ;
Paradigma funcional
Basa la descripción del cómputo en la evaluación de funciones o la aplicación de funciones a valores conocidos. Por ello se les llama a veces a los lenguajes de este paradigma como lenguajes aplicativos. Un lenguaje de programación funcional posee como mecanismo básico la evaluación de una función o el llamado de función.
Este abarca, junto a la evaluación de la función, el paso de valores como parámetros a la función y la obtención de resultados como valores retomados desde las funciones. El paradigma funcional no comprende la noción de variable o asignación a variables. Las operaciones repetitivas no son expresadas por ciclos (los que requieren variables de control para su terminación) sino por funciones recursivas.
El estudio de las funciones recursivas ha establecido la siguiente propiedad: "Un lenguaje de programación es Turing-completo si tiene valores enteros, funciones aritméticas sobre esos valores y se tiene un mecanismo para definir nuevas funciones usando funciones ya existentes, selección y recursión”
Ejemplo Reescritura funcional del cálculo del máximo común divisor (en Modula-2) Procedure gcd (u,v: integer): integer; Begin If v= 0 then Return v; else Return gcd(v, u mod v); end; End gcd;
Note que este código no tiene variables locales ni ciclos, pero se usa recursión y la instrucción Return para indicar el valor retornado por la función. El mismo ejemplo expresado en LISP, que es un representante del paradigma funcional:
(define (gcd u v) (if (= v 0) u (gcd v (remainder u v)) ) )
Paradigma de la programación lógica
Está basado en la lógica simbólica. En un lenguaje de programación lógica un programa consiste de un conjunto de enunciados que describen qué se cumple acerca del resultado deseado, contrario a dar una secuencia particular de instrucciones que tienen que ser ejecutadas en un orden fijo para dar el resultado.
Todo lo que necesita un programa lógico es establecer las propiedades del cómputo. Por ello a la programación lógica se le reconoce a menudo como una forma de programación declarativa ya que son declaradas propiedades y no secuencias de ejecución.
Ejemplo
El gcd de u y v es u si v= 0. El gcd de u y v es igual al gcd de v y u mod v si v es > 0.
Traducido a Prolog:
gcd(u,v,u):- v = 0 . gcd(u,v,x):- v > 0 , y is u mod v, gcd (v,y,x) .
En Prolog, un programa es una secuencia de enunciados llamados claúsulas, que tienen la forma: a:- b, c, d que corresponde a la aserción que “a se cumple si b, c y d se cumplen. Prolog requiere variables para representar valores. Sin embargo, las variables no representan localizaciones de memoria como en la programación imperativa, sino nombres para cómputos parciales.
En el programa Prolog, gcd tiene 3 parámetros en vez de dos, el tercero representa el valor calculado, ya que en si gcd es sólo verdadero o falso (se satisface o falla)
Programación Orientada a Objetos
La programación orientada a objetos (POO) fue creada para superar las insuficiencias de la programación estructurada, aprovechando sus mejores ideas.
Su principal preocupación durante el desarrollo de programas es determinar los objetos que representarán, de una forma más adecuada, los elementos presentes en un problema, una vez determinados estos, se pasa a determinar cuales con sus características o atributos principales y cuales son las acciones (procedimientos) que son realizados con tales atributos y que por tanto caracterizan su comportamiento.
La programación orientada a objeto tiene como objetivos facilitar el desarrollo y comprensión de programas de gran porte y posibilitar la reutilización de código.
Las principales características que identifican a un lenguaje orientado a objeto son los conceptos de clases, herencia y polimorfismo.
A diferencia de otros paradigmas de programación, el paradigma orientado a objetos es tanto un estilo de programación como una metodología para el desarrollo de sistemas de computación.
Lenguajes relacionados
Bibliografía
Texto básico Maestría Ciencias de la computación, Universidad Popular de Nicaragua.