“evaluar” un lenguaje?

Anuncio
¿Cómo “evaluar” un lenguaje?
También es importante determinar cuando un lenguaje es eficiente, para esto existen
determinados criterios o características que nos ayudan, cabe mencionar que no existen
lenguajes buenos o malos sino apropiados e inapropiados para una determinada situación o
problema. Para esto cada autor refleja según su criterio que características importantes debe
cubrir un lenguaje para un buen desempeño del mismo, cabe mencionar, que los lenguajes
son diseñados e implementados, por esta razón es necesario conocer todos los puntos de
vista.
CRITERIOS DE LENGUAJE SEGÚN DORIS APPLEBY Y JULIUS
VANDEKOPPLE
 Definiciones bien definidas. Los programadores de Fortran o Pl/1 trabajan a
menudo como un grupo. Si uno no sabía o había olvidado como escribir el código
para efectuar una tarea particular, la cosa más fácil por hacer era bajar al vestíbulo y
preguntarle a un amigo. Los manuales eran volúmenes inmensos pobremente
organizados que enseñaban mediante ejemplos con más frecuencia que por
cualquier otro medio.
 Sintaxis BNF y EBNF. Los diseñadores de Algol 60 rectificaron esto al
proporcionar una sencilla descripción del lenguaje en 18 páginas. La sintaxis del
lenguaje está descrita en los forma Backus Naur (BNF), seguida de ejemplos de
programación. BNF es un ejemplo de un metalenguaje, un lenguaje utilizado
para describir otro lenguaje, en este caso uno de programación. BNF tiene
símbolos llamados metasímbolos, y reglas propias, las cuales son empleadas
para definir la sintaxis del lenguaje particular de programación en cuestión.
Por sintaxis entendemos una colección de instrucciones formada al seguir un
conjunto de reglas que diferencian los programas válidos de los no válidos. La
sintaxis por sí misma no da significado a un lenguaje; meramente define la
colección de frases y sentencias que son combinaciones válidas de los caracteres
del lenguaje. Este punto lo estudiaremos en la unidad 2.
 Semántica. Un lenguaje también debe de estar definido semánticamente al
describir la manera precisa lo que significa una construcción particular. Por
ejemplo, la expresión (X < 3) significa en pseudocódigo que X debe tener un
valor; ese valor es comparable al entero 3, y la expresión es verdadera si el valor
es menor que 3, y es falsa en otros casos. El lenguaje natural es notoriamente
ambiguo, de manera que hace esfuerzos para describir formalmente la semántica
del lenguaje así como también la sintaxis.
 Comprobabilidad. Probar con certeza matemática que un programa es correcto es
un proceso lento. Sin embargo, C.A.R. Hoare cree que “las ventajas prácticas de la
comprobación de programas eventualmente se sobrepondrán a las dificultades, en
vista de los costos creciente de los errores de programación”. La prueba de que un
programa es correcto involucra tres pasos: primero la comprobación de que el
programa cumple con la intención del programador; segundo la prueba de que el
compilador traduce de manera correcta a código máquina la sintaxis y la semántica
del lenguaje empleado; y tercero, que se compruebe que la máquina misma
funciona correctamente.
Una meta para cualquier lenguaje de programación es probar que un compilador para el
lenguaje lo interpreta de manera precisa. Esto es a menudo difícil de hacer si la definición
del lenguaje incluye descripciones en lenguaje natural de lo que se desea mediante un trozo
particular de sintaxis, si la sintaxis puede describirse en un lenguaje formal, y la semántica
puede escribirse axiomáticamente, un compilador puede ser probado formalmente para
satisfacer por completo tanto la definición sintáctica como la semántica del lenguaje.
La sintaxis de Pascal fue definida en BNF, y su semántica definida axiomáticamente por su
diseñador Nicklaus Wirth, en colaboración con C.A.R. Hoare. El PL/1 fue diseñado
utilizando la definición Viena (VDL, Vienna Definition Language) y Algol 68 fue definida
en una gramática vW de dos niveles (llamada así por el nombre de su inventor, A. van
Wijngaarden) que era demasiado enigmática para la mayoría de los usuarios. Estos últimos
dos metalenguajes forman bases para comprobación de compiladores. Si un lenguaje está
definido en VDL, incluye una descripción de lo que pasa cuando cada declaración del
lenguaje se ejecuta teóricamente en una computadora teórica. Si un compilador implementa
fielmente la computadora teórica, puede probarse que la ejecución del programa es
correcta. La gramática vW no describe una computadora teórica, pero permite que parte de
la semántica que trata con declaraciones sea definida en la gramática. Por lo tanto no
pueden generarse programas correctos gramaticalmente que vuelvan a declarar variables o
que las definan de una manera inconsistente.
 Confiabilidad. El software se considera confiable si se comporta como es
anunciado y produce los resultados que el usuario espera. Cuando se presenta un
error, debería ser fácilmente detectado y corregido. Un lenguaje de programación
fomenta la escritura de programas confiables de maneras a menudo sutiles. La
declaración goto es quizá la característica más notoria de lenguaje pensada para dar
como resultado programas no confiables. El problema que subyace aquí es que los
programas con muchos gotos, hacia atrás y hacia adelante son difíciles de leer para
cualquiera que no sea su creador, y por lo tanto difíciles de modificar y de depurar.
Las características de sintaxis poco usuales también pueden fomentar errores. El lenguaje C
utiliza = como un operador de asignación. X=5 asigna el valor de 5 a la localidad de
almacenamiento designada para X. Para hace comparaciones se utiliza ==. X == 5 compara
el valor de X con 5 y si es verdadero o falso, dependiendo si X es igual o no a 5. Puesto que
C permite asignaciones casi en cualquier sitio de una declaración, la substitución
inadvertida de = por el símbolo poco familiar == puede no producir un error, únicamente
resultados ininteligibles. Los identificadores tanto en Modula como en C son sensibles a la
capa tipográfica de las letras. Así cuenta y Cuenta representan variables distintas, que son
confundidas fácilmente tanto por un programador como por un revisor subsecuente.
Un lenguaje confiable debería ser capaz de manejar errores durante el tiempo de ejecución
una sobrecarga (overflow) aritmética ocurre cuando se calcula un entero que es mayor de lo
que puede ser soportado por el hardware particular involucrado. Puede presentarse gran
variedad de errores durante la entrada de datos, desde la lectura al pasar el final de un
archivo hasta un valor no permitido introducido de manera interactiva. Estas clases de
errores son llamadas excepciones y las provisiones del lenguaje para tratar con ellas se
llaman manejadores de excepciones. La interrupción de un programa no siempre es
aceptable, en particular para las aplicaciones en tiempo real.
Para los lenguajes de programación, la confiabilidad por lo general se refiere a los
mecanismos que promueve la escritura, mantenimiento y depuración de los programas
correctos, y el subsecuente manejo de excepciones cuando un programa se ejecuta.
 Traducción rápida. Los lenguajes de
programación que se consideran en esta materia,
generalmente son independientes de la máquina. Es
decir, un programa escrito en el lenguaje puede ser
traducido y ejecutado en una variedad de máquinas
diferentes. Un programa que escribimos se encuentra
en código fuente. Este debe ser traducido a un lenguaje
que una máquina particular pueda reconocer, y por último en código de máquina
que pueda ejecutarse en realidad. La máquina en la que un programa se ejecuta se
denomina anfitrión y su(s) lenguaje(s), lenguaje(s) anfitrión(es). Colocamos la (s)
opcional después del lenguaje porque una máquina puede tener más de un lenguaje
anfitrión. Cualquier máquina debe tener un lenguaje asociado de máquina de bajo
nivel escrito en código binario. También puede tener un lenguaje ensamblador de
nivel superior específico de la máquina. Con frecuencia resulta práctico traducir
primero el código fuente a código intermedio, el cual es intermedio entre el código
de máquina y el código fuente. El código intermedio puede ser o puede no ser uno
de los lenguajes anfitrión.
La traducción del código fuente involucra tres pasos: análisis lexicográfico, análisis
sintáctico y análisis semántico. El análisis lexicográfico, o rastreo, identifica cuáles tokens
representan valores, identificadores, operadores, etc. El análisis sintáctico, llamado
simplemente sintáctico, reconoce las declaraciones no válidas del lenguaje fuente. El
análisis semántico determina el significado de una declaración. Algunos traductores pueden
realizar dos o más de estos tres procesos en un solo paso sobre el código fuente.
Los traductores son intérpretes o generativos, los cuales generan un código intermedio. Un
intérprete es en sí mismo un programa que traduce una expresión o declaración de lenguaje,
calcula y luego imprime o utiliza de otro modo su resultado. Los intérpretes son por lo
regular más fáciles de escribir que los traductores generativos, pero se ejecutan más
lentamente. Una ventaja de un intérprete es que los errores de ejecución así como los de
sintaxis son detectados a medida que se encuentra cada declaración, eliminando así
cualquier duda acerca de dónde reside el problema. Los lenguajes Lisp y Prolog tienen
tanto intérpretes como compiladores, siendo los primeros utilizados para el aprendizaje y la
experimentación, donde los resultados línea por línea son deseables. Un compilador es
generalmente más ventajoso para programas extensos.
Las partes más comunes de un traductor generativo son el compilador, el ligador y el
cargador. El compilador traduce el código fuente a código intermedio orientado a la
máquina, denominado código objeto. El ligador enlaza de manera conjunta código
intermedio compilado independientemente en un solo módulo de carga, resolviendo las
diferencias entre tokens. Su salida puede estar en el mismo código intermedio como su
entrada pero está libre de referencias de un módulo a otro. El código resultante es así
relocalizable, puesto que contiene cualquier información que necesita y es independiente de
otros segmentos del programa. El cargador hace la traducción final en código máquina y
carga el programa en diversas localidades de memoria. La salida del cargador es un módulo
ejecutable en código de máquina. Durante cada fase, se hacen entradas en varias tablas que
mantienen el registro de los tipos variables, direcciones de memoria, etc.
Es importante en algunos casos, por ejemplo una aplicación interactiva, que el código
fuente se traduzca rápidamente. Por otro lado, si un programa se va a compilar solamente
una vez y va a ejecutarse a menudo, la velocidad de compilación puede no ser una
preocupación principal. Se han hecho intentos exitosos para compiladores de un paso, los
que rastrean el código fuente sólo una vez, mientras que algunos traductores efectúan
muchos pasos (por ejemplo, algunos de los primeros compiladores Pl/1 de IBM, que
ejecutan más de 30 pasos para compilar un programa completo). Algunos factores que
afectan el número de pasos necesarios para un compilador en particular son:
1. ¿Cuánta memoria está disponible? ¿Pueden caber simultáneamente en la
memoria tanto el código fuente como el código objeto que están siendo
generados?
2. ¿Qué tan rápido es el compilador mismo y cuanta memoria requiere?
3. ¿Qué tan grande es el programa objeto y que tan rápido debe ejecutarse? ¿Debe
optimizarse el código objeto?
4. ¿Qué clase de características de depuración se requieren para el código fuente?
5. ¿Qué clases de detección y recuperación de errores se requieren para el código
ejecutable?
6. ¿Cuántas personas estarán involucradas en la escritura del compilador? ¿Podría
ser ventajoso permitir que cada una escriba un paso independiente realizando
una fase simple del proceso de compilación?
 Código objeto eficiente. Después de que el código fuente se compila en código
objeto, no se hace referencia adicional al lenguaje fuente. Así es en tiempo de
compilación que los asuntos de la eficiencia en el uso de memoria y tiempo de
ejecución deben ser considerados. Existe generalmente un balance comparativo
entre el trabajo que el programador debe hacer y el trabajo que el compilador puede
hacer. Por ejemplo, un lenguaje que tiene todas las declaraciones de tipo y de
variables precediendo a otro código puede asignar todas las localidades de memoria
en un momento, acelerando la compilación. Por supuesto el programador tendrá que
hacer estas declaraciones entes que un programa pueda ser compilado.
Algunos compiladores, llamados compiladores de optimización, ejecutan uno o dos pasos
más después del análisis semántico para incrementar la eficiencia del código compilado.
Las primeras optimizaciones, tales como la eliminación de subexpresiones comunes son
independientes de la máquina, mientras que las mejoras finales dependen de la máquina
particular en la que el programa se ejecutará. Los lenguajes de muy alto nivel, donde los
programas manipulan estructuras complejas tales como registros, listas, relaciones o
conjuntos, dependen de compiladores de optimización por eficiencia. Los lenguajes de
programación ejecutan la gama de los parecidos a C, donde el programador puede trabajar
muy cerca del CPU mismo, hasta lenguajes de manipulación de bases de datos (DML, por
sus siglas en inglés), donde las estructuras físicas subyacentes están profundamente ocultas.
En los lenguajes de menor nivel, un código objeto eficiente refleja con frecuencia la
habilidad o capacidad de los escritores de compiladores.
 Ortogonalidad. La palabra ortogonal viene del griego y se refiere a líneas rectas
cruzándose en ángulos rectos. Las variables aleatorias se consideran ortogonales.
Con esto queremos decir que los componentes son independientes entre sí y que se
comportan en la misma manera en cualquier circunstancia.
Un ejemplo se encuentra en los conceptos de tipo y funciones. Un tipo describe la
estructura de los elementos de datos, Una función es un procedimiento por el que pasa un
número finito de valores de parámetro y devuelve un único valor hacia el procedimiento
que la invoca. En un lenguaje ortogonal, los tipos son independientes de las funciones, y no
se aplican restricciones a los tipos de parámetros que pueden ser pasados o al tipo de valor
que puede ser devuelto. Así, podríamos ser capaces de pasar una función a una función, y
recibir una función de regreso. Lisp incorpora esta característica particular, pero deben
comprenderse ciertas dificultades inherentes y tratar con ellas.
Algol 68 fue pensado y diseñado como un lenguaje completamente ortogonal. Tiene muy
pocas construcciones integradas, y el programador es capaz de construir lo que quiera
mediante la combinación de diversas características. Nunca llegó a ser popular en los
Estados Unidos, en parte debido a que era demasiado ortogonal. Los programadores
querían estructuras especiales que se comportaran de maneras predecibles.
La no ortogonalidad puede ser molesta y conducir a errores. Para el programador novato en
Pascal, parece no haber una buena razón por la que una función no pueda devolver un
registro o por la que un archivo deba ser pasado como un parámetro var.
 Generalidad. La generalidad está relacionada con la ortogonalidad. Se refiere a la
existencia de sólo características necesarias del lenguaje, con las otras compuestas
en una manera libre y uniforme sin limitación y con efectos previsibles. Como
ejemplo de una carencia de generalidad, considere la del tipo de unión libre en
Pascal. Una unión libre es un registro que puede tener un campo que varía
dependiendo de su uso. En un registro de esta clase, la variable de campo variante
puede funcionar como un apuntador y no ser directamente accesible para impresión
u otros usos. En otro momento durante la misma ejecución, puede ser tipificado
(declaración de tipos) como un entero, con su valor disponible para impresión,
operaciones aritméticas, etc. Esta característica no es general, porque la localidad de
memoria relacionada con las variables de campo variante no se trata de manera
uniforme y los efectos no son previsibles.
 Consistencia en notaciones comunes. Como hemos mencionado antes, los
problemas para solución por computadora con frecuencia son concebidos en el
lenguaje de las matemáticas. De este modo, la notación de los lenguajes de
programación debería ser consistente con las notaciones comúnmente usadas en este
campo. Usamos “-“ para indicar resta y números negativos. Así, 5-3 y –5 deberían
permitirse en lenguajes que soporten aritméticas de enteros.
1 ∈{1,2,3} es la notación común para la pertenencia a un conjunto, y por ello es preferible
a la versión en Pascal 1 In [1,2,3]. Sin embargo, no todos los conjuntos de caracteres
soportan ∈, {, y }, de modo que en ocasiones se hacen sustituciones.
 Uniformidad. La consistencia está relacionada con la uniformidad (en algunos
casos es llamada regularidad). Con esto queremos decir que nociones similares
deberían verse y comportarse de la misma manera. Una cuestión de uniformidad
tiene que ver con la necesidad de tener inicios y finales. ¿Debería todo “fin” estar
precedido por un “inicio” correspondiente? De manera similar, ¿debería toda
declaración finalizar con un signo de punto y coma (;)? En un lenguaje
completamente uniforme, la respuesta debería ser sí a ambos asuntos.
 Subconjuntos. Un subconjunto de un lenguaje es una implementación de sólo una
parte del mismo, sin características especiales. Las especificaciones originales para
el lenguaje Ada del DOD no permiten subconjuntos. La motivación para esto fue el
deseo del DOD para hacer que sus contratistas produjeran software que explotará un
Ada con todas sus características. Después de todo, las características innecesarias
no fueron incluidas. Una de las desventajas de este enfoque era que los estudiantes
no podían empezar a aprender el lenguaje hasta que tuvieran disponibles
compiladores completamente validados; por esta razón no existió un cuerpo de
programadores hasta varios años después de que el lenguaje había sido completado.
Algunos lenguajes son extensos, con muchos componentes especiales. Éstos pueden
ejecutarse solamente en máquinas grandes y no están disponibles para compañías y
escuelas más pequeñas a menos que se trate de un subconjunto de los mismos. Otra ventaja
de los subconjuntos es el desarrollo incremental de un lenguaje. Con esto nos referimos a la
versión inicial de un lenguaje de núcleo pequeño, con otras características que van siendo
liberadas a medida que se van desarrollando.
 Extensibilidad. El inverso de los subconjuntos es la extensibilidad. Un lenguaje
puede tener un núcleo estándar, el cual es invariable en cada implementación, pero
con varias extensiones. Las ventajas de los subconjuntos son mejoradas cuando un
lenguaje puede ser extendido en formas útiles. A principios de 1968, los
desarrolladores de Cobol adoptaron este enfoque mediante la definición de un
“núcleo” que todos los compiladores debían satisfacer. Once módulos
estandarizados fueron agregados los cuales pueden o no pueden ser incluidos en
cualquier compilador Cobol dado. Ada 95 ha adoptado un enfoque modular
semejante.
Los diseñadores de Pascal incluso usaron otro enfoque, definiendo un pequeño lenguaje
estándar portátil que carecía de algunas características deseables, tales como capacidades de
gráficos y manejo de cadenas de caracteres. Los implementadores de Pascal agregaron
varias mejoras, las cuales hicieron a sus compiladores atractivos para los programadores,
pero los programas resultantes eran menos portátiles. Por ejemplo, el Pascal estándar no
tiene tipo de cadenas (string), pero casi todos los compiladores de Pascal proporcionan uno
integrado en el lenguaje mismo o en un módulo especial para ser incluido con la mayoría de
los archivos fuente.
 Transportabilidad. Un lenguaje es transportable si sus programas pueden
compilarse y ejecutarse en diferentes máquinas sin tener que reescribir el código
fuente. Para conseguir la transportabilidad se han establecido las organizaciones
estándares nacionales e internacionales para producir descripciones de lenguajes a
las cuales deben adherirse las implementaciones. Las más activas de éstas son el
Instituto Americano de Estándares (ANSI), la Institución Británica de Estándares
(BSI) la Organización Internacional de Estándares (ISO) y el Instituto de Ingenieros
Eléctricos y Electrónicos (IEEE). Éstos grupos tienen varios comités oficiales que
preparan y revisan estándares para diferentes lenguajes.
Los estándares pueden desarrollarse después de ganar alguna experiencia con un lenguaje
en particular, como es el caso de Pascal, o antes de que un lenguaje sea diseñado, como
ocurre con Ada. La estandarización temprana puede perpetuar características de diseño
deficientes no reconocidas, al tiempo que demora el fomento de dialectos incompatibles.
Lisp es quizás el lenguaje con la mayor longevidad no estandarizada. Lisp fue diseñado e
implementado a principios de los años sesenta, pero es solamente hasta ahora que se está
estandarizando a Common Lisp. Sin embargo, la parte estandarizada será solamente un
pequeño núcleo, con diferentes implementadores libres de hacer cualquier extensión que
ellos deseen.
PROPIEDADES DE UN BUEN LENGUAJE SEGÚN JORGE CASTRO Y
OTROS
 Aspectos de diseño
 Claridad, simplicidad y unidad de conceptos. Un lenguaje de programación ha
de suministrar al programador un conjunto de conceptos claros, simples y
unificados, de manera que puedan ser usados como primitivas para el diseño de
algoritmos con esta finalidad, es deseable tener un número pequeño de
conceptos distintos y que las reglas para combinarlos sean tan simples y
regulares como sea posible.
 Sintaxis y semántica bien definidas. La necesidad de una sintaxis y una
semántica bien definidas es necesario ya que por una parte una definición
sintáctica formal nos puede asegurar la inambigüedad y completitud del
lenguaje y, por otra, la definición formal de la semántica obligará a que todas las
implementaciones de éste se comporten igual.
De la misma manera también es importante dar al lenguaje una sintaxis clara
que lo haga legible. La legibilidad tiene su contrapunto en la facilidad para
escribir programas, especialmente respecto a la rapidez, por eso, en ciertos
casos, puede ser deseable que el lenguaje sea críptico – para incrementar la
rapidez en la escritura de los programas – y, por tanto que pierda legibilidad.
 Consistencia con las notaciones usuales. Es la propiedad de que las cosas
signifiquen lo que uno espera que signifiquen. Por ejemplo, que los símbolos de
operación sean los usuales, las palabras claves tengan un uso relacionado con lo
que significan, o bien que si definimos constructores que ya aparecen en otros
lenguajes su significado no sea diferente.
 Soporte para la abstracción. Debido a que en muchos casos el conjunto de
operaciones y tipos de datos básicos está muy lejos de lo que querríamos a la
hora de resolver un problema, el lenguaje nos ha de dar mecanismos para poder
abstraer: poder crear tipos de datos nuevos y asociarles nuevas operaciones,
poder definir diferentes niveles dentro de un programa y tratarlos por separado,
etc.
 Independencia de la máquina. La máquina sobre la que se trabaja no debe
condicionar la programación. Esta propiedad está ligada a la portabilidad, es
decir, la capacidad de mover programas de una máquina a otra. Esto se
consideraba una faceta esencial para los lenguajes de alto nivel, pero en muchos
casos (especialmente en los lenguajes imperativos) no se ha cumplido.
 Verificabilidad. En principio, se trata de que los programas sean verificables
formalmente. Esta propiedad, además, garantiza una cierta legibilidad en los
programas.
 Redundancia. Es una propiedad muy importante a la hora de detectar errores.
Un ejemplo de redundancia (repetición de información) sería la definición
explícita de variables, pues el solo hecho de usarlas ya nos dice que son
variables y también de qué tipo son. La redundancia puede permitir detectar
errores tipográficos, por ejemplo, al escribir una variable, ya que el nombre que
hayamos escrito por error (si no es por casualidad) no estará definido. En
general, es muy importante que los errores se detecten cuanto antes mejor,
porque cuanto más se tarde en detectarlos más costoso será corregirlos.
 Ortogonalidad. Un lenguaje de programación ha de tener sólo un conjunto de
herramientas básicas, comprensibles por separado y sin ningún tipo de iteración
cuando se combinan. Esto quiere decir esencialmente que haya pocas
excepciones dentro del conjunto de cosa que podemos hace combinando los
diferentes elementos del lenguaje.
 Aspectos de Implementación.
 Portabilidad. Para muchos proyectos, la portabilidad del programa resultantes es
un criterio muy importante, pues las computadoras donde se desarrollen los
programas no son normalmente los mismos que habrán de ejecutarlos
finalmente. Ya hemos visto que esta propiedad de las implementaciones de un
lenguaje depende directamente de dos aspectos del diseño: la independencia de
la máquina y la definición formal de semántica.
 Soporte Externo. La existencia de un entorno de trabajo apropiado puede hacer
que un lenguaje, en principio menos potente, sea más fácil de usar que uno más
potente que no tenga este soporte. Dentro de este entorno podemos incluir, por
ejemplo, programas para encontrar errores (debuggers) o editores especiales que
agilicen el proceso de creación de programas.
 Calidad del compilador o intérprete. Si se trata de un compilador incluye el
costo (en tiempo) de traducción, como la calidad del código generado. Según el
tipo de objetivo que tengamos (si tenemos que compilar muy a menudo y
después ejecutar muy poco, bien al revés), potenciaremos más la eficiencia en
un sentido o en otro. Si el lenguaje es interpretado, entonces se refiere a la
eficiencia (en tiempo) de la interpretación.
 Bajo costo de mantenimiento. Muchos estudios han demostrado que la mayor
parte del costo que implica cualquier programa que use durante un cierto
período de tiempo (años), no está en el costo inicial del diseño e
implementación, sino en el mantenimiento que recibe una vez instalado. Este
mantenimiento incluye la reparación de errores o las extensiones del programa
para responder a nuevas necesidades y es hecho, posiblemente, por
programadores que no son los que hicieron el programa inicialmente. Por lo
tanto, un lenguaje que permita la modificación, reparación, y extensión a lo
largo del tiempo de programas por parte de diferentes programadores, puede
reducir notablemente los costos.
 Documentación. Este punto sólo hace referencia a la necesidad de disponer de
una buena documentación sobre el lenguaje. Esta documentación se compondrá
de diversos manuales: de la implementación del lenguaje, de los complementos
del entorno, etc.
CRITERIOS DE EVALUACIÓN SEGÚN TERRENCE PRATT
 Claridad, sencillez y unidad de los conceptos del Lenguaje. 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 mucho 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 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. Llamamos a este atributo Integridad Conceptual. Esta claridad de semántica
y de conceptos es el factor determinante del valor de un lenguaje
 Claridad en la sintaxis del programa. La sintaxis de un lenguaje afecta la
facilidad con la que un programa puede escribirse, probarse y más tarde entenderse
y modificarse. La facilidad de lectura (legibilidad) de un programa en un lenguaje es
una consecuencia central aquí. Una sintaxis que sea particularmente breve o
enigmática con frecuencia hace que un programa sea fácil de escribir (por el
programador con experiencia), pero difícil de leer cuando el programa debe
modificarse posteriormente. Los programas APL a veces resultan tan enigmáticos
que sus propios diseñadores no pueden descifrarlos con facilidad unos meses
después de que los terminaron. Muchos lenguajes contienen construcciones
sintácticas que fomentan la dificultad de lectura, produciendo dos instrucciones casi
idénticas que significan realmente dos cosas distintas. Por ejemplo la presencia de
un solo carácter blanco en un proposición Snobol4 puede alterar completamente su
significado. Un lenguaje debe tener la propiedad de que las construcciones que
tienen un significado diferente también tengan un aspecto diferente: por ejemplo, las
diferencias semánticas deben reflejarse en la sintaxis del lenguaje.
Para el programador no basta que una sintaxis no sea engañosa o propensa a errores sino
que además debe ser una sintaxis que usada adecuadamente permita que las estructuras
lógicas señaladas en el algoritmo. En el enfoque de programación conocido como
programación estructurada, los lenguajes se diseñan jerárquicamente de arriba hacia abajo
(del programa principal a los subprogramas de niveles más bajos), usando sólo un conjunto
restringido de estructuras de control en cada nivel - secuencias de instrucciones simples,
iteraciones y ciertos tipos de ramificación condicional. Cuando se hace en forma adecuada,
las estructuras algorítmicas resultantes son fáciles de entender, depurar y modificar. En
forma ideal debería ser posible traducir tal programa directamente a instrucciones de
programación adecuadas que reflejaran la estructura del algoritmo. Con frecuencia la
sintaxis del lenguaje no permite tal codificación directa. Por ejemplo, Fortran se basa en
etiquetar las proposiciones e instrucciones goto como estructuras de control y proporciona
poca alternativas. Por eso la forma de un programa Fortran no se puede hacer de manera
ordinaria para reflejar con mucha claridad la estructura de control del algoritmo adyacente,
y gran parte del esfuerzo utilizado en el desarrollo de un algoritmo estructurado es posible
que se pierda en la traducción al Fortran. Esto es parte de la controversia que provoca el uso
del goto, lo cual se verá en la unidad de control de secuencias. uno de los argumentos
principales que favorecen a Pascal sobre Fortran en la enseñanza de la programación
introductoria, a pesar de que se este se utilizaba mucho, es que Pascal favorece al diseño
elegante de los programas.
 Ortogonalidad. El término ortogonalidad se refiere al atributo de ser capaz de
combinar varias características de un lenguaje en todas las combinaciones posibles,
de manera que todas ellas tengan un 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 falso o
verdadero. 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 de
aprender y de 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 un extremo ineficiente. A causa de estas cualidades en
oposición, la ortogonalidad como atributo de un diseño de lenguaje es todavía motivo de
controversia, pues a ciertas personas le s gusta y a otras no.
 Naturalidad para la aplicación. El lenguaje debe proporcionar estructuras de
datos adecuadas, operaciones, estructuras de control y una sintaxis natural para
resolver un problema. Una de las razones principales de la proliferación de
lenguajes es justamente esta necesidad de naturalidad. Un lenguaje ajustado
particularmente a cierta clase de aplicaciones puede simplificar mucho la creación
de está área. Es importante mencionar que los algoritmos secuenciales, algoritmos
concurrentes, algoritmos lógicos, etc. Todos ellos tienen estructuras naturales
diferentes que están representadas por programas en esos lenguajes.
Cobol, para aplicaciones en negocios incluyendo el manejo de archivos; Snobol4, para
procesamiento de cadenas; Prolog con su predisposición hacia propiedades deductivas y
c++ para diseño orientado a objetos son lenguajes con una inclinación obvia a clases
particulares de aplicaciones.
 Apoyo para la abstracción. Aun con el lenguaje más natural para una aplicación,
hay una brecha sustancial de las estructuras de datos abstractos y las operaciones
que caracterizan la solución de un problema con las estructuras de datos
particulares de datos primarios y operaciones construidas en un lenguaje. Por
ejemplo, Pascal puede ser un lenguaje apropiado para construir un programa que
haga el horario de clases de una universidad pero las estructuras de datos abstractos
de “estudiante”, “clase”, “instructor”, “salón de lectura” y las operaciones abstractas
de “asignar un estudiante a una clase”, “planear una clase en un salón de lectura”,
etc., que son naturales de la aplicación no son proporcionadas directamente por
Pascal. Una parte substancial de la tarea del programador es diseñar las
abstracciones usando las características más primitivas proporcionadas por el
lenguaje de programación real. El lenguaje debe ayudar sustancialmente o impedir
la expresión de estas abstracciones. En teoría debe permitir que las estructuras de
datos, tipos de datos y operaciones definan y mantengan como abstracciones
contenidas por sí mismas, para que el programador pueda emplearlos en otras partes
del programa conociendo sólo sus propiedades de abstracción sin importar los
detalles de su implementación. Casi todos los lenguajes proporcionan mecanismos
de subprogramas para definir las operaciones de abstracción, pero la mayoría son
muy débiles en su soporte de otros tipos de abstracción a excepción de los lenguajes
de Ada y C++.
 Facilidad para verificar programas. La confiabilidad de programas escritos en un
lenguaje es casi siempre una preocupación central. 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 la verificación de escritorio, es
decir, verificar visualmente el texto del programa; se puede poner a prueba
ejecutándose con los datos de entrada de prueba y comparando los resultados de
salida con las especificaciones, etc. Para programas grandes se suele emplear la
combinación de algunos de estos métodos. El uso de un programa que dificulta la
verificación de programas puede ser 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 afectas su utilidad. La presencia de un entorno 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 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 a la medida para el lenguaje pueden acelerar mucho la creación y puesta a
prueba de los programas. Los recursos para el mantenimiento y modificación de
múltiples versiones de un programa puede simplificar mucho el trabajo con
programas grandes. Uno de los lenguajes que ofrece un entorno de programación
compuesto es el Smalltalk
 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 para otros sistemas de computadoras. Un
lenguaje que está ampliamente disponible y cuya definición es independiente de las
características de una máquina en 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 lenguajes cierto control sobre las características
transportables del lenguaje.
 Costo de uso. 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 de los programas. En los primeros días de la computación,
las cuestiones de costo se referían casi exclusivamente a la ejecución de los
programas. Era importante el diseño de compiladores que optimizaran 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 del lenguaje 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 máquinas de escritorio que trabajan a varios
millones de instrucciones por segundo y que están ociosas la mayor parte del
tiempo, se puede tolerar el incremento de un 10 o 20% del tiempo de ejecución
si ello significa un mejor diagnóstico o un control más fácil por parte del 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 traducción eficiente, más que la ejecución
eficiente, puede ser de importancia capital. Típicamente los programas
estudiantiles se compilan muchas veces cuando se están depurando pero se
ejecutan sólo pocas veces. En casos así, es importante contar con un compilador
rápido y eficiente en vez de un compilador que produzca un código 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 lenguajes Smalltalk.
Para una 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
el esfuerzo totales que se invierten 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 programas. Muchos estudios han demostrado que el
costo más grande que interviene en cualquier programa que se utiliza a lo largo
de un período de años no es el costo del diseño, codificación y prueba inicial del
programa, sino los costos totales del ciclo vital, que incluye 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 a 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 requieren para satisfacer nuevas
necesidades. Un lenguaje que facilita la modificación, reparación y extensión
frecuente del programa por parte de diferentes programadores durante un
período de varios años puede ser a la larga, mucho menos costoso que usar
cualquier otro.
FUNDAMENTOS DE LOS
LENGUAJES SEGÚN ROGER S.
PRESSMAN.
 Tipos de datos y tipificación. Hoy en día, el
mérito de un lenguaje de programación moderno
se juzga por algo más que sintaxis y la amplitud
de construcciones procedimentales. La
tipificación de datos y los tipos de datos
específicos soportados por un lenguaje de
programación son un aspecto importante en la calidad del lenguaje. Un objeto de
datos hereda un conjunto de atributos fundamentales del tipo de datos al que
pertenece. Un objeto de datos puede tomar un valor que se encuentre dentro del
rango de valores legítimos del tipo de datos y puede ser manipulado por operaciones
que se apliquen a ese tipo de datos
Los tipos de datos simples abarcan un amplio rango que incluye los tipos numéricos, tipos
enumerados, tipos lógicos y tipos de cadena. Los tipos de datos más complejos engloban
estructuras de datos engloban estructuras que van desde los array simples unidimensionales
hasta las estructuras de listas y los complejos y heterogéneos arrays y registros.
Las operaciones que se pueden realizar sobre un tipo de datos particular y la forma en que
se pueden manipular distintos tipos en una misma sentencia se controlan por la
comprobación de tipos incorporada en el intérprete o compilador del lenguaje de
programación. Fairley define cinco niveles de comprobación de tipos que se encuentran
normalmente en los lenguajes de programación.
 Nivel 0: sin tipos. Los lenguajes de programación sin tipos no incluyen medios
explícitos para la tipificación de datos y, por lo tanto, no conllevan ninguna
comprobación de tipos. Los lenguajes ANSI estándar de algunos como Basic,
Apl, Lisp, e incluso Cobol entran dentro de esta categoría. Aunque cada
lenguaje permite al usuario definir las estructuras de datos, la representación de
los datos contenida en cada objeto de datos esta predefinida.
 Nivel 1: coerción automática de tipos es un mecanismo de comprobación de
tipos que permite al programador mezclar diferentes tipos incompatibles,
permitiendo así que se den las operaciones requeridas. Por ejemplo Pl/1 asigna
un valor numérico de 0 al valor lógico false (falso) y un valor numérico de 1 al
valor lógico true (verdadero). Así, las operaciones aritméticas, aplicadas
normalmente a tipos de datos numéricos, se pueden aplicar a tipos de datos
lógicos en Pl/1.
 Nivel 2: modo mixto conversión de tipos es similar en muchos aspectos a la
coerción automática de tipos. Para que se pueda dar una determinada operación,
diferentes tipos de datos dentro de una misma categoría de tipos, se convierten a
un único tipo destino. La aritmética de modo mixto de Fortran permite que se
usen números enteros y reales en una misma secuencia de lenguajes de
programación.
 Nivel 3: comprobación de tipos pseudorrígida tiene todas las características de
la fuerte comprobación de tipos, pero que se implementan de forma que existan
una o más vías escapes. Por ejemplo aunque Pascal, comprueba la
compatibilidad de interfaces dentro de un mismo programa compilado, no lo
hace para procedimientos compilados por separado – un escape en la aplicación
de la fuerte comprobación de datos.
 Nivel 4: fuerte comprobación de tipos se da en lenguajes de programación que
sólo permiten llevar a cabo operaciones entre objetos de datos que sean del
mismo tipo de datos previamente especificado. La comprobación de tipos se
lleva a cabo sobre los operadores, los operandos y las interfaces de los
subprogramas, tanto en tiempo de compilación como en tiempo de carga y en
tiempo de ejecución. Los compiladores de Ada llevan a cabo una fuerte
comprobación de tipos.
 Subprogramas. Un subprograma es un componente de un programa compilado por
separado que contiene datos y estructuras de control. Generalmente se le menciona
con el nombre de módulo como una manifestación genérica del subprograma.
Dependiendo del lenguaje de programación, un subprograma se puede denominar
subrutina, procedimiento, función u otro nombre especializado. Sin tener en cuenta
cual sea el nombre, el subprograma tiene un conjunto de características genéricas
 Una sección de especificación que incluye su nombre y la descripción de la
interfaz.
 Una sección de implementación que incluye los datos y las estructuras de
control
 Un mecanismo de activación que permite que el subprograma sea requerido
desde cualquier punto del programa.
En los lenguajes de programación convencionales, cada subprograma es una entidad en sí
misma, operando sobre los datos en la forma que dictan las estructuras de control de un
programa mayor. En lenguajes de programación orientados a objetos, el punto de vista
clásico del subprograma es reemplazado por el de objeto.
 Estructuras de Control. Es un nivel fundamental, todos los lenguajes de
programación modernos permiten al programador representar secuencias,
condiciones y repetidores – las construcciones lógicas de la programación
estructurada. La mayoría de los lenguajes de programación modernos proporcionan
una sintaxis para la especificación directa del “if then else”, del “do while” y del
“repeat until” (así como el case). Otros lenguajes, como Lisp y Apl, requieren que el
programador emule esas construcciones dentro de los límites de sintaxis del
lenguaje.
Además de las construcciones prodecimentales básicas de la programación estructurada,
puede haber otras estructuras de control. La recursividad crea una segunda activación de un
subprograma durante la primera activación. O sea, el subprograma se llama a sí mismo
como parte del procedimiento definido, la concurrencia da soporte a la creación de
múltiples tareas, a la sincronización de tareas y a la comunicación de tareas en general esta
característica del lenguaje es de mucho valor cuando se llevan a cabo aplicaciones de tipo
real. El manejo de excepciones es una característica del lenguaje que atrapa los errores del
sistema o los definidos por el usuario, pasando el control a un manipulador de excepciones
para que los procese.
 Soporte para el enfoque orientado a objetos. En teoría, la creación de objetos y la
construcción de software orientado a objetos se puede llevar utilizando cualquier
lenguaje de programación convencional (por ejemplo, C o PASCAL). Pero en la
práctica, el soporte para métodos orientados a los objetos debe estar incorporado
directamente en el lenguaje de programación que se vaya a utilizar para
implementar un diseño orientado a objetos
Un lenguaje de programación orientado a objetos debe proporcionar un soporte directo para
la definición de clases la herencia, la encapsulación y el paso de mensajes. Además de estas
construcciones orientadas a los objetos, muchos de estos lenguajes implementan
características adicionales, como herencia múltiple y polimorfismo (diferentes objetos que
pueden recibir mensajes con el mismo nombre).
La definición de clases es fundamental en un enfoque orientado a los objetos. Un lenguaje
de programación orientado a los objetos define un nombre de clase y específica los
componentes privados y públicos de la clase. Para ilustrar la forma general de las
construcciones orientadas a los objetos vamos a utilizar C++. Se puede definir una clase,
denominada “contador”, de la siguiente forma:
class contador
{
private :
unsigned int valor;
public :
contador ( );
void incrementar ( );
void decrementar ( );
unsigned int acceder_valor ( );
};
A partir de la definición básica de la clase se puede obtener una nueva clase, de la siguiente
manera:
class contador_especial: public contador
{
una copia de todos los datos privados de contador
private :
Datos privados de contador_especial;
…
};
Los objetos derivados de la clase “contador_especial” pueden utilizar todos los métodos
definidos para la “clase madre” contador. La definición de una clase encapsula las
abstracciones de los datos y los componentes del programa (métodos) que operan sobre
dichos datos. En C++, los mensajes se envían a los objetos (la instanciación de una clase)
de la siguiente forma:
Nombre_objeto.mensaje (argumentos);
Donde nombre_objeto identifica el objeto y mensaje (argumentos) describe el mensaje a
enviar.
Los detalles de implementación y la terminología para las definiciones de clases, herencia,
encapsulación y paso de mensajes puede variar dependiendo del lenguaje. Por ejemplo, el
lenguaje de programación Smalltalk define una clase de la siguiente manera
 Definición: identifica a la clase.
 Datos privados: atributos cuyos valores son privados de las instancias
individuales de la clase.
 Datos compartidos: atributos cuyos valores son compartidos por todas las
instancias de la clase.
 Diccionarios: atributos cuyos valores son compartidos por múltiples clases.
 Métodos de instancia: los procedimientos que implementan mensajes que se
pueden enviar a las instancias de la clase.
 Métodos de clase: los procedimientos que implementan mensajes que se pueden
enviar a la propia clase (por ejemplo: inicialización de los datos compartidos)
Aunque estos términos difieren ligeramente de los usados en la definición de C++, el
concepto fundamental de clase permanece igual. De forma parecida, la herencia, la
encapsulación y el paso de mensajes, se implementan con una sintaxis diferente, pero con
los mismos fundamentos semánticos. Cualquier construcción está disponible en cualquier
lenguaje que verdaderamente sea orientado a objetos.
CARACTERÍSTICAS DE UN BUEN LENGUAJE SEGÚN ALLEN B.
TUCKER
 Expresividad. La habilidad de un lenguaje para reflejar claramente el significado
deseado por el diseñador del algoritmo, por lo que, permite que una declaración se
establezca compactamente y refuerce el uso de sentencias asociadas con la
programación estructurada
 Bien definido. Que la sintaxis y semántica del lenguaje no contengan
ambigüedades, son internamente consistentes y completas. Entonces el
implementador de un lenguaje bien definido debe tener dentro de su definición una
especificación completa de todas las formas expresivas del lenguaje y sus
significados. El programador, por la misma virtud, debe poder predecir exactamente
el comportamiento de cada expresión antes de que realmente se ejecute. Por lo
tanto, los lenguajes bien definidos aumentan la transportabilidad y la prueba.
 Tipos y Estructuras de Datos. La habilidad de un lenguaje para soportar una gran
variedad de valores de datos y colecciones no elementales de éstos. Los últimos
incluyen principalmente a los arrays y registros, pero no excluye a las estructura de
datos dinámicas, tales como listas, colas, pilas y árboles.
 Modularidad. Esta características tiene dos aspectos:
 El soporte del lenguaje para la subprogramación, es decir, la habilidad de
definir procedimientos y funciones independientes y comunicarlos vía
parámetros o variables globales con el programa llamador.
 La extensibilidad del lenguaje en el sentido de permitir operadores y tipos de
datos definidos por el programador
 Facilidades de Entrada – Salida. En las Entradas y Salidas de un lenguaje,
nosotros estamos examinando cómo soporta los archivos de acceso secuencial,
indexado y directos, así como las funciones sobre base de datos y de recuperación
de Información. Los archivos de datos generalmente residen sobre el
almacenamiento secundario. Un archivo es normalmente demasiado grande para
que todos sus registros quepan en la memoria, al mismo tiempo y, por lo tanto se les
aplican diferentes estrategias de programación.
 Transportabilidad. Es cuando el lenguaje que está implementado en distintas
computadoras. Esto es, su diseño es relativamente independiente de la máquina. Los
Estándares de los lenguajes generalmente son más transportables.
 Eficiencia. Permite la ejecución y traducción rápida sobre las máquinas en dónde
está implementado.
 Pedagogía. La facilidad de enseñar y aprender, existencia de mejores libros de
texto, están implementados en un entorno de desarrollo de programas mejor; son
ampliamente conocidos y usados por los mejores programadores en el área de
aplicación.
 Generalidad. Que el lenguaje sea útil en un amplio rango de aplicaciones de
programación.
CRITERIOS DE EVALUACIÓN DE LOS LENGUAJES SEGÚN ROBERT
SEBESTA
 Legibilidad. Uno de los más importantes criterios para juzgar a un lenguaje de
programación es la facilidad con la cual los programas pueden ser leídos o
entendidos. Antes de 1970, el desarrollo de software fue intentado largamente en los
términos del código de escritura. En la década de 1970, sin embargo el ciclo de
vida de los conceptos de software fue desarrollado; la codificación fue relegada a
una representación en un papel más pequeño y el mantenimiento fue reorganizado
como gran parte del ciclo, esto en los términos de costo. Porque la facilidad de
mantenimiento es determinada en gran parte por la legibilidad de los programas, la
legibilidad es un punto muy importante en de la calidad de programas y los
lenguajes de programación.
 Sencillez. Dentro de las características que contribuye a la legibilidad de un
lenguaje de programación es la sencillez, la cual puede afectar fuertemente a la
legibilidad. Un lenguaje que tiene un gran número de componentes elementales
es más difícil de aprender que uno que contenga un número pequeño. Los
programadores que utilizan los lenguajes de programación tienen la tendencia de
aprender una parte de los mismos sin embargo ignoran otras características de
ellos. Esta razón muchas veces es utilizada como pretexto, cuando el lenguaje
tiene un gran número de componentes o elementos, pero este argumento no es
válido. Los problemas de legibilidad ocurren cuando el programador aprende de
una forma diferente una aplicación, con la cual el analista este familiarizado.
Teniendo también muchas características no es solamente el detrimento de la simplicidad
del lenguaje Otro problema es la multiplicidad de características, es decir, tener más de una
forma determinada para realizar una operación en particular. Por ejemplo, en el lenguaje C
se puede incrementar una simple variable entera de cuatro diferentes maneras:
Contador = contador + 1
Contador =+ 1
++ contador
contador ++
Aunque la última sentencia tiene una pequeña diferencia semántica en comparación con las
otros en algunos usos, las cuatro tiene el mismo significado cuando son usadas como
expresiones estando solas.
Un tercer problema potencial es el operador sobrecargado, en el cual un simple símbolo
operador tiene más de un significado. Aunque esto es una característica útil, puede reducir
la legibilidad al leer si los usuarios están permitiendo ellos mismos la generación de
sobrecarga y ellos no lo hacen evidentemente. Por ejemplo, es claramente aceptada la
sobrecarga del signo + para usarlo en la suma tanto de enteros como de reales o punto
flotantes. En efecto esta sobrecarga simplifica un lenguaje porque reduce el número de
operadores. Sin embargo, supuestamente, la definición del programador del signo + usado
entre arreglo de dimensión simple puede significar la suma de todos los elementos de
ambos arreglos. Porque el significado usual de la adición de vectores es completamente
diferente de esto, puede hacer más confuso el programa para ambos, el autor y los lectores.
Un nivel de ejemplo más extremo de la confusión de programa puede ser un usuario
definiendo el signo + usado entre dos vectores para significar la diferencia entre los
primeros elementos de los mismos.
Las sentencias del lenguaje pueden ser también muy simples. Por ejemplo la sintaxis y el
significado de las sentencias del lenguaje ensamblador son un modelo de simplicidad. Es
muy simple, sin embargo hacer programas en lenguaje ensamblador es poco legible. Porque
ellos carecen por completo de sentencias de control, su estructura es más sutil, porque sus
sentencias son más simples, para realizar mejor esto se requiere un lenguaje equivalente de
alto nivel
 Ortogonalidad. Ortogonalidad en un lenguaje de programación significa que
hay una pequeña relación entre un conjunto de construcciones primitivas que
pueden ser combinados en un numero relativamente pequeño de manera que se
pueden construir las estructuras de control y de datos en el lenguaje. Además,
cada combinación posible de primitivas es legal y significativa así, la
ortogonalidad sigue de una simetría de lazos entre primitivos, mientras un
concepto del uso de ortogonalidad en el diseño puede ser ilustrado comparando
un aspecto de los lenguajes ensamblador de los ordenadores centrales de la IBM
y de la serie de VAX de superminicomputadoras. Nosotros consideraremos
solamente una sola situación simple, la de agregar dos valores numéricos de 32bit que residen o en memoria o en un registro y substituir uno de los dos valores
con suma para este propósito, la unidad IBM tiene dos instrucción que tienen la
siguiente forma:
A Reg1, memory_cell.
R
Reg1, Reg2
Donde Reg1 y Reg2 representan registros. La semántica de ellos es
Reg1  contenido(reg1) + contenido (memory_cell)
Reg1  contenido(reg1) + contenido(reg2)
La instrucción de adición VAX para valores enteros de 32 bits es
ADDL operando1, operando2
La semántica de la misma es:
Operando2  contenido(operando1) + contenido(operando2)
En este caso, cualquier operando puede ser uno colocado en una celda de memoria con una
instrucción.
El diseño de VAX tiene ortogonalidad por que aquí con una sola instrucción se puede
utilizar para colocar, en la celda memoria, un operando. Hay dos maneras de especificar el
operando, que puede ser la combinación en cualquier manera concebible. El diseño IBM
diseñar no es ortogonal. Solamente dos combinaciones de operaciones son legales fuera de
las cuatro posibilidad, y se requiere dos diferente instrucciones, A y AR. El diseño IBM es
ser más estricto y por lo tanto menos fácil de escribir, por ejemplo, usted no puede agregar
un valor y colocarle el valor en una localización de memoria. Además, el diseño de IBM es
más difícil de aprender debido a las restricciones y adiciones de la instrucción.
La ortogonalidad se relaciona de cerca con la simplicidad: cuanto más ortogonal es el
diseño de un lenguaje, menos son las excepciones que se requieren de las reglas del
lenguaje. Pocas excepciones significan un grado más alto de regularidad en el diseño, que
hace que el lenguaje sea más fácil de aprender, leer y entender. Cualquiera que ha
aprendido una parte significativa del lenguaje inglés puede atestiguar la dificultad de la
multiplicidad de aprender las excepciones de una regla (por ejemplo, i antes de e excepto
después c).
Sin embargo Pascal es un moderno lenguaje relativo, su diseño fue un largo
número de tipos de reglas inconsistentes para ser seguidas. Los procedimientos
pueden tener a los dos tipos de parámetros “var” y “value”, a menos que el
procedimiento mismo lo pase como un parámetro. La función puede retornar
solamente tipos no estructurados. Un parámetro de tipo formal para ser
llamado; ello no puede ser completado con la descripción de tipos. Los
archivos no pueden ser pasados por valor. La lista de regla en y en. En otras
palabras los tipos de reglas de Pascal no son ortogonales.
Demasiado ortogonalidad también puede causar problemas. Quizás el lenguaje de
programación más ortogonal es ALGOL 68. Cada construcción del lenguaje en ALGOL 68
tiene un tipo, y no hay restricciones en esos tipos. Además, la mayoría de las
construcciones producen valores. Esta libertad de combinaciones permite construcciones
extremadamente complejas. Por ejemplo, los símbolos condicionales pueden aparecer como
los izquierdos en las asignaciones, junto con la declaración y otras declaraciones
clasificadas, mientras el resultado es una localización. Esta forma extrema de ortogonalidad
conduce a una innecesaria complejidad. Además, porque los lenguajes requieren una gran
cantidad de primitivas, un alto grado de ortogonalidad da lugar a una explosión de la
combinación. Tan incluso si las combinaciones son simples, sus números escarpados
conducen a la complejidad. La simplicidad en un lenguaje, por lo tanto, es por lo menos en
parte un resultado de una combinación de un número relativamente pequeño de
construcciones primitivas y del uso limitado del concepto del ortogonalidad.
Algunos creen que los lenguajes funcionales ofrecen una buena combinación de la
simplicidad y de ortogonalidad. Un lenguaje funcional es aquél que: sus operaciones son
hechas aplicando funciones a parámetros dados. En contraste, los lenguajes imperativos,
tales como C y PASCAL, las operaciones se especifican sobre todo con variables y
declaraciones de asignación. El Lisp es actualmente el lenguaje más extensamente usado
que utiliza la programación funcional. El Lisp no es un lenguaje funcional puro, porque
también contiene algunas características de lenguaje imperativo. Los lenguajes funcionales
ofrecen potencialmente la simplicidad total más grande porque pueden lograr todo con una
sola construcción, la llamada de la función, que, se puede combinar con otras llamadas de
funciones de manera simple. Esta elegancia simple es la razón por la que atraen al
investigador de muchos lenguajes a los lenguajes funcionales, como alternativa primaria a
los lenguajes no funcionales complejos, tales como Ada y PL1
 Sentencias de Control. La programación estructurada revoluciona en la década
de 1970 fue un reacción para la pobre legibilidad causada por la limitadas
estructuras de control de algunos lenguajes surgidos en la décadas de 1950 y
1960. Particularmente, se reconoció ampliamente que el uso indiscriminado de
las declaraciones del goto reduce seriamente la legibilidad del programa. Los
programas que se pueden leer de arriba hacia abajo (top –down) son mucho más
fáciles de entender que los programas que requieren saltar visualmente la lectura
del programa a partir de una declaración a otra declaración no adyacente para
seguir el orden de la ejecución. Sin embargo, en cierto lenguaje, los gotos que
ramifican hacia arriba son a veces necesarios; por ejemplo, se requieren para
construir los ciclos MIENTRAS QUE en FORTRAN 77. Sin embargo, las
siguientes restricciones del goto puede hacer que los programas sean menos
legibles:
1. Deben preceder sus tarjetas, exceptúan cuando están utilizados en los ciclos
2. Que sus tarjetas deben nunca ser demasiado distantes.
3. El número de gotos debe ser limitado
Las versiones de Basic y de FORTRAN que estaban disponible en los años 70 le faltaban el
control de sentencias que permitían fuertes restricciones en el uso de gotos, así que los
programas eran altamente legibles pero la escritura en esos lenguajes era difícil. La
mayoría de los lenguajes de programación se diseñaron desde los últimos años de la década
de 1960, sin embargo, han incluido suficientes sentencias de control que se necesitaban
para eliminar en las declaraciones el uso de goto. Así, el diseño de las sentencias de control
en un lenguaje puede ser un factor importante para la legibilidad de los programas escritos
en ese lenguaje.
 Estructura de Datos. La presencia de facilidades adecuada para la definición de
estructuras de datos en un lenguaje es otra característica significativa de la
legibilidad. Por ejemplo, se supone que un tipo de dato entero es usado para una
bandera indicadora porque no hay tipos de datos boleanos en los lenguajes. En
tal lenguaje, nosotros podemos tener una sentencia semejante a la siguiente:
Suma_es_muy_grande ≔ 1
Mientras este significado no es muy claro, entonces en un lenguaje que incluye los tipos
booleanos nosotros podemos tener la sentencia:
Suma_es_muy_grande ≔ true
Entonces este significado es perfectamente claro, de manera similar, los tipos de datos
registro proveen un método para representar como se emplean los registros que es más
legible que usar una colección de arreglos: un arreglo para cada ítem de dato en un registro
empleado, el cual es mas usado en los lenguajes que no tiene el tipo registro

Diseño de sintaxis. La sintaxis o forma de los elementos de un idioma tiene un
efecto significante en la legibilidad de los programas. Lo siguientes son tres
ejemplos de diseño sintáctico de opciones que afectan la legibilidad

Forma de los identificadores. Los identificadores restringidos a longitudes
muy cortas disminuyen la legibilidad, si los identificadores pueden tener seis
caracteres a lo sumo, como en FORTRAN 77, no es a menudo posible usar
nombres connotativos para las variables. Un extremó más es el ejemplo del
Instituto Nacional Estándar Americano original (ANSI) (BASIC) (ANSI
197b) en que un identificador pudiera consistir de una sola carta seguida de
otra.
La posibilidad del carácter de conexión como lo raya baja de los identificadores es una gran
ayuda a la legibilidad SUMA_DE_CUADRADOS en ciertamente el que
SUMADECUADRADOS.
Se discuten otros problemas del plan acerca de las formas de identificadores en el capítulo
4.

Las palabras especiales. La apariencia y la legibilidad del programa es
fuertemente influenciado por las formas de palabras especiales de un idioma
(por ejemplo begin, end, y for) especialmente importante en el método de
formar declaraciones compuestas o grupos de las declaraciones
principalmente en estructuras del mundo. Varios idiomas usan emparejando
pares de palabras especiales o símbolos para formar grupos. Pascal requiere
begin, los pares del extremo a los grupos de las formas para todo el mando
de estructuras excepto repeat, declaraciones en las que ellas pueden omitirse
(otros ejemplos de la falta de Pascal es la ortografía). C usa abrazaderas
para el mismo propósito. Los dos de estos idiomas sufren porque siempre se
termina los grupos de las declaraciones de la misma manera, que hechuras si
es difícil determinar que grupos esta acabándose cuando un extremo
aparece.
FORTRAN 77 y ADA hacen a este el que despeja cuando una sintaxis del cierre distinta
para cada tipo de grupos de las declaraciones para los ejemplos, ADA usa un extremo si
para terminar una estructura de la selección y vuelta del extremo para una estructura de la
vuelta. Esto es y ejemplo de conflicto entre simplicidad que es el resultado de usar palabras
reservadas, como en Pascal, y la legibilidad mayor que los resultados de usar palabras
reservadas, como ADA.
Otro problema importante si se pueden usar las palabras especiales de un idioma como
nombres para las variables del programa. En ese caso, los programas resultantes pueden ser
muy confusos, por ejemplo en FORTRAN 77 la apariencia especial de estas palabras en un
programa puede o no encontrar algo especial.

Forma y significado. Declaraciones anteriores para que en su apariencia, por
lo menos parcialmente, indica que su propósito es una ayuda obvia a al
legibilidad. Semántica o significado debe seguir directamente de la sintaxis
o apariencia. En algunos casos, este principio es violado a través de dos
idiomas por las estructuras que son similares en apariencia pero tienen
significados diferentes.
En FORTRAN 77, por ejemplo, hay dos declaraciones, el GOTO asignado y los GOTO
computados cuyas apariencias son muy similares pero cuyo los significados son diferentes,
aunque los dos son múltiples saltos alejados. Por ejemplo, las declaraciones
GO TO (10, 20, 30), I
GO TO I, (10, 20, 30)
Se usa bastante diferentemente. En el primero, la variable I es de tipo ENTERO; en el
segundo, etiqueta valores. Una de las quejas primarias sobre los órdenes de la cáscara de
siempre haga pensar en su función. Por ejemplo, el comando grep de UNIX puede ser
descifrado a través de conocimientos anteriores, o quizás la destreza y familiaridad con el
editor, ed de UNIX. Su apariencia no connota nada a los principiantes de UNIX. En ed
[comando/ expresión_reguladora] busca una subcadena igual a la expresión_reguladora.
Precediendo esto con hechuras de g, haciendo de esto un comando global que hace que el
archivo entero se revise hasta alcanzar la búsqueda. Siguiendo el comando con p se
especifica esa línea con la subcadena equivalente para que se imprima. Para que el
g/expresión_reguladora/p, pueda abreviarse, por su puesto como grep, las impresiones de
todas las líneas en un archivo que contiene subcadena que son iguales a la
expresión_reguladora
 Fácil Escritura. Escriturabilidad es que la medida de qué fácilmente un lenguaje
puede usarse para crear programas para un dominio del problema escogido. La
mayoría de las características del lenguaje que también efectúan legibilidad la
escriturabilidad de efecto. Esto sigue directamente del hecho que el proceso de
escritura un programa exige la frecuencia del programador de releer las porciones
del programa existente.
Rescriturabilidad debe ser considerado en el contexto del dominio del problema designado
de un lenguaje en el reino de una aplicación particular y el otro no era. Por ejemplo, la
escriturabilidad de COBOL y APL es extremadamente diferente para crear un programa
para tratar con estructura de datos bidimensionales, por que de los dos APL es ideal. Sus
escriturabilidades también son bastante diferentes para la pizca de los informes producto
de los formatos complejos, para eso es la finalidad por lo que COBOL se diseñó.
Las subdivisiones siguientes describen los factores más importantes que influyen en la
escriturabilidad de un lenguaje
 Sencillez y Ortogonalidad. Sí un lenguaje, tiene una gran cantidad de diversas
construcciones, algunos programadores pueden no ser familiares con todos
ellos. Esto puede conducir a un uso erróneo de algunas características y de un
desuso de otros que puedan ser más elegantes o más eficientes, o ambos, que los
que se utilicen. Esto puede ser posible, según lo observado por Hoare, para
utilizar características desconocidas accidentalmente, cuando los resultados son
extraños.
Por lo tanto, un número pequeño de primitivas construcciones y del conjunto de las reglas
constante para combinarlas (esto es ortogonalidad) es mucho mejor que simplemente
teniendo una gran cantidad de números primitivos. Un programador puede diseñar una
solución para un problema complejo después de aprender solamente un conjunto simple de
construcciones primitivas.
En la misma vena, demasiada ortogonalidad puede ser detrimento de la fácil escritura. Los
errores en programas de la escritura pueden ir desapercibidos cuando casi cualquier
combinación de primitivos es legal. Esto puede conducir a las absurdidades en el código
que puede no ser descubierto por el compilador.
 Soporte para la abstracción. Abreviadamente, medios de la abstracción, la
capacidad de definir y después de utilizar las estructuras complicadas de
operaciones de manera que muchos de los detalles. La abstracción es un
concepto dominante en los lenguajes de programación contemporáneos. Esta es
reflexión del rol central que las abstracciones juegan en la designación de las
metodologías de la programación moderna. El grado de la abstracción que
permite un lenguaje de programación y la naturaleza de sus expresiones es muy
importante para su codificación.
Un ejemplo simple de un proceso de abstracción es el uso de un subprograma en la
implementación de un algoritmo, que en ejecución se requiera varias veces en un programa.
Saliendo del subprograma, el código tendría que ser replegado en todos los lugares donde
sea necesario, que haría el programa mucho más largo y más aburrido para la escritura. Más
importante, si el subprograma no fue utilizado, el código del subprograma podría ser
eliminado del algoritmo y así evitar, el entorpecimiento del flujo del código.
Como ejemplo de la abstracción de los datos, considere un árbol binario que salve datos del
número entero en sus nodos. Un árbol binario sería puesto en ejecución generalmente en
FORTRAN 77 en tres matrices paralelas del número entero, donde dos de los números
enteros se utilizan como subíndices para especificar nodos del descendiente. En PASCAL,
estos árboles pueden ser implementados usando una abstracción de un nodo del árbol en la
forma de una unidad de registro simple con dos punteros y un número entero. Lo natural de
la última representación hace mucho más fácil escribir un programa de PASCAL que
utilice un árbol binario que para escribir uno en el FORTRAN. El dominio de la solución
del problema del lenguaje está más cercano al dominio del problema. La ayuda total para
la abstracción es claramente un factor importante en la codificación del lenguaje.
 Expresividad. La expresividad en un lenguaje puede referirse a varías
características diferentes. En un lenguaje como APL, sus operaciones existentes
cuentan con poderosos operadores que permiten un problema grande de
computación pueda realizarse con un pequeño programa. Generalmente los
medios que un lenguaje tiene son relativamente cómodos antes que incómodas
rutas de especificación computacional.
Por ejemplo, en C, la expresión Contador++ es
más cómoda y más pequeña que Contador =
Contador + 1. También el operador boleano AND
THEN de Ada es un camino cómodo para
especificar la valoración de expresiones booleanas
de corto circuito. La inclusión de la declaración
FOR en Pascal hace más fácil de escribir ciclos
que con el uso de WHILE. Todo esto ayuda a incrementar la facilidad de escritura en un
lenguaje de programación.
 Confiabilidad. Un programa es confiable si ejecuta sus especificaciones bajo todas
las condiciones. Aunque una meta deseable en los lenguajes de programación es la
facilidad para permitir el diseño de programas confiables, pero no es completamente
claro que ésta sea una característica para la estimación y comparación entre los
lenguajes de programación.
 Legibilidad y Fácil Escritura. Ambos facilidad de escritura y la legibilidad
implica confiabilidad un programa escrito en un lenguaje que no soporta formas
naturales para expresar los algoritmos requeridos necesitara métodos de uso
menos posible corregir en todas las situaciones. El programa más fácil para
escribir, es el más conveniente para corregir. Legibilidad da confiabilidad en
ambas fases del cielo de vida de mantenimiento y escritura. Los programas que
son difíciles para leer también son difíciles de escribir y modificar.
 Verificación de Tipos. La verificación de tipos es probar la compatibilidad de
los tipos entre dos variables o una variable y una constante, es de algún modo la
relación de uno con otro. Dos de las formas más comunes de tales impedimentos
son los operadores de las operaciones aritméticas y el resultado de la operación,
teniendo en cuenta ambas partes (izquierda y derecha) del signo de asignación.
La verificación de tipos es un factor importante en la confiabilidad del lenguaje.
Esto se debe a que la verificación de tipos en el tiempo de ejecución es bastante
cara, por lo que es más deseable la verificación de tipos en el momento de la
compilación. Además que permite de una manera más fácil la detección de
errores, por lo que es menos costoso la reparación de los mismos. En el diseño
de los lenguajes contemporáneos, como el ADA, se requiere la verificación de
tipos de casi todas la variable en tiempo de compilación, salvo en el caso de que
el usuario utilice estados explícitos entonces la verificación de tipos se
suspende. Esto elimina la posibilidad de errores en tiempo de ejecución en los
programas realizados en ADA.
La manera de cómo fracasa la verificación de tipos tanto en tiempo de compilación como
en el de ejecución, es manejado por los innumerables errores de los programas que
envuelven a los parámetros de los subprogramas en el lenguaje C. En este programa el tipo
de parámetros reales en una llamada a función no se verificaba para determinar si
correspondiente parámetro formal de la función era el mismo. Por ejemplo una variable de
tipo int puede ser usada como parámetro real en una llamada a una función que espera un
float en su parámetro formal, por lo que el compilador descubre el problema de la
inconsistencia en el tiempo de ejecución, por lo que da como resultados una serie de
Problemas, recurso del cual es con frecuencia difícil de determinar (En respuesta a este
problema, el sistema “UNIIX” incluye un programa de utilidad llamado “LINT” que checa
programas en C para dichos problemas), Métodos de parámetros – paso y subprogramas
son discutidos en el capítulo 8.
En General, el rango escrito de una variable de un arreglo es parte del tipo de chequeo.
Por eso el chequeo del rango escrito es parte del tipo de chequeo, aunque debe ser
realizado al momento de correrlo. Porque muchos tipos son checados en Pascal, los rangos
del algoritmo también son checados. El chequeo es extremadamente importante para la
confiabilidad del programa, debido aquel rango de salida de algoritmo con frecuencia causa
errores que no aparecen hasta mucho después de las violaciones actuales.
 Manejo de Excepciones. La habilidad de un programa para detectar errores al
momento del corrido, así como otras condiciones inusuales, para tomar medidas
correctas y para continuar es una gran ayuda de confiabilidad. Esta facilidad es
llamada Manejo de excepción; El lenguaje “Ada” incluye capacidades extensas
para manejo de excepción, pero las facilidades son prácticamente no existen en
muchos lenguajes usados como Pascal, C, y Fortran.

Restricción de Alias. De manera holgada el alias quiere decir que se tienen dos
métodos de referencia distintos, o dos nombres, para la misma celda de memoria.
Ahora es muy aceptado que el alias represente un peligro en un lenguaje de
programación, lo anterior, porque a la mayoría de los lenguajes de programación
se les permite hacer algunos tipos de alias, por ejemplo: variables equivalentes
en Fortran y punteros en Pascal. En ambos casos, las dos variables de diferentes
subprogramas pueden significar la misma celda de memoria; algunos tipos de
restricciones de alias pueden ser prevenidos por la designa aún del lenguaje.
En algunos lenguajes, el alias es usado para prevenir deficiencias en la facilidad
de abstracción de datos del lenguaje. Otros lenguajes restringen extremadamente
el alias para incrementar su confiabilidad.
 Costo. El costo total de los lenguajes de programación es
una función de muchas de estas características. Los primeros
costos de entrenamiento y el costo de la escritura del
programa en un lenguaje puede reducirse significativamente
en un buen ambiente de programación.
 Entrenamiento del programador. Esta es una función de la simplicidad y
ortogonalidad del lenguaje, esto aproxima en propósito a una aplicación en
particular, y a la experiencia de los programadores. Aunque el más poderoso de
los lenguajes no necesita ser duro para leer, y ellos frecuentemente lo son.
 Escritura del programa. Esta es una función de la fácil escritura de los
lenguajes. El esfuerzo original para diseñar e implementar un lenguaje de alto
nivel es manejado por el deseo para bajar el costo de creación de software.
 Compilación. El tercero es el costo de compilación de los programas en el
lenguaje. Un impedimento principal para el uso adelantado de Ada fue la
prohibición de los altos costos de ejecución en la tercera generación de los
compiladores Ada. Este problema es conveniente en compiladores menos
seguros como el Ada llega a ser el más apropiada.
 Ejecución. El cuarto es el costo de ejecución de programas escritos en un
lenguaje es influenciado grandemente por el diseño del lenguaje. Un lenguaje,
tal como el PL1, que requiere mucho tiempo de ejecución para la verificación de
los tipos impide que el código se ejecute rápidamente, a pesar de la calidad del
compilador.
 Mantenimiento. Finalmente tenemos al costo de mantenimiento de programas,
con la cual se incluyen las correcciones y modificaciones para añadir nuevas
características. El costo de mantenimiento depende de un gran número de
características del lenguaje especialmente la legibilidad. Porque el
mantenimiento es realizado frecuentemente por otras personas diferentes al
autor original del software, la pobre legibilidad puede hacer lar tarea
extremadamente desafiante. La importancia del mantenimiento del software no
puede ser desafiante. Esto se ha estimado para un software de aplicación de
aplicación con una vida relativamente larga, los costos de mantenimiento
pueden subir de dos a tres cuartos de tiempo tanto como el desarrollo.
Todas estas contribuciones para los costos de un lenguaje nos indican que hay dos muy
importantes: el de desarrollo y el de mantenimiento de los programas. Porque son las
funciones de legibilidad y fácil escritura las que intervienen en ellos, y éstos son los dos
criterios más importantes en la evaluación de los lenguajes de programación.
Una nota final para el criterio. Los criterios, especialmente legibilidad y escriturabilidad, no
se pueden precisar en su definición ni limitarse de una manera exacta. Los conceptos son
útiles sin embargo nos proporcionan una perspicacia en el diseño y evaluación de los
lenguajes de programación. Existen por supuesto otros criterios para la evaluación de los
lenguajes de programación, por ejemplo la portabilidad (la facilidad con el que el programa
puede ser movido de una máquina a otra), su generalidad (la aplicación del lenguaje a un
extenso ramo de aplicaciones) y sobre todo Buenas Definiciones (la integridad y precisión
del lenguaje en la definición de la documentación). Sin embargo las que hemos explicado
consideramos que son las más importantes.
Descargar