Programacion I

Este es el resumen que hice para estudiar la asignatura de Programación I, en la carrera de Ingeniería Técnica de Informática de Gestión en la UNED.

Esta asignatura utiliza el lenguaje de programación MODULA-2. Es un lenguaje demasiado obsoleto, pero muy bueno para aprender a programar en cualquier lenguaje, por lo estricto que es.

Repito, es un resumen. Mientras lo transcribía he visto que está muy resumido, no se puede utilizar a modo de documento de consulta, si no mas bien como recordatorio.

Introduccion

Maquinas y programas

Maquinas programables

El concepto de maquina lleva asociado el de un proceso de funcionamiento en el que las diferentes operaciones se realizan de forma sucesiva o simultánea

Desde el punto de vista del funcionamiento, las clasificamos:

Concepto de computo:
Un computo es una operación de tratamiento de información. En informática identificamos el concepto de computo con el de tratamiento de la información

Concepto de computador:
Un computador se define como una maquina programable para tratamiento de la información

Un programa de computador es una descripción de un computo. Ademas es también una descripción del comportamiento de una maquina y podemos considerarlo como una maquina virtual

Un computador posee elementos fijos (maquina base -> Hardware) y modificables (programas -> software) La estructura general de un computador se puede representar

Memoria
Procesador
Datos de entrada Entrada / Salida Resultados de salida

Programación e ingeniería de software:
Para realizar un determinado tratamiento de información con ayuda de un computador habrá sido necesario:

Programación
El desarrollo de programas complejos exige un equipo mas o menos numeroso de personas que trabajan de manera organizada. Las técnicas para desarrollo constituye la ingeniería de software

Programación e ingeniería del software no son disciplinas independientes si no complementarias

El desarrollo de software en gran escala consiste en descomponer el trabajo total en programación en partes independientes para ser desarrollada por miembros individuales.

Objetivos de la programación
Las técnicas de programación han de establecerse con el objetivo de ser una base adecuada para la ingeniería del software

Los objetivos particulares de la programación:

Si tenemos que ordenar los distintos objetivos, primero la corrección, segundo la claridad y tercero la eficiencia

Lenguajes de programación

Cada modelo de computador podrá utilizar una forma particular de codificación de programas que no tiene por que coincidir con la de otros modelos

Código de maquina ó Lenguaje de maquina: la forma de codificar de una maquina en particular

Un programa codificado en el lenguajes de un modelo de maquina, no podrá ser ejecutado en otro distinto. Para que funcione en diferentes maquinas tenemos que preparar versiones particulares para cada maquina, lo que multiplica el costo del desarrollo

El código maquina es muy difícil de leer por personas, esta compuesto por código numérico sin sentido

Los lenguajes de programación sirven para representar programas en forma texto para que pueda ser leído por una persona con facilidad, ademas, son formas de representación independiente de la maquina que lo vaya a usar

Compiladores e interpretes
Procesadores de lenguajes: Realizan el tratamiento de la información en forma de texto que representa el programa en el lenguaje de programación simbólico

Un compilador es un programa que traduce programas de un lenguaje de programación simbólico a código maquina

Programa fuente o lenguaje fuente; A la representación del programa en lenguaje simbólico

Programa objeto o lenguaje objeto: A la representación del programa en código maquina

Interprete es un programa que analiza la descripción simbólica del programa fuente y realiza las operaciones oportunas

El proceso mediante interprete es mas sencillo, que mediante compilador, ya que no hay que realizar dos fases. Su principal inconveniente es que su ejecución es mas lenta.

Modelos abstractos de computo
El modelo abstracto recoge los elementos básicos y formas de combinación en forma abstracta, prescindiendo de la notación concreta usada en cada lenguaje de programación para representarlo.

Hay diversos modelos:

Modelo funcional: Se basa en el empleo de funciones
Modelo de flujo de datos: Cada operador esta conectado mediante un cuadrado con entradas y salidas
Modelo de programación lógica: Un programa consiste en plantear de manera formal un problema a base de declarar una serie de elementos conocidos.
Modelo imperativo: Responde a la arquitectura Von Neumann. Aparece como una lista de ordenes o instrucciones.

Elementos Basicos de la Programacion Imperativa

Notación BNF

Elemento_no_terminal: Este estilo se emplea para escribir el nombre de un elemento gramatical que habrá de ser definido por algún regla. Cualquier elemento a la izquierda del metasímbolo ::= será no terminal y aparecerá con este estilo.

Elemento_terminal: Este estilo se emplea para representar los elementos que forman parte del lenguaje Modula-2, es decir, que constituyen el texto de un programa. Si aparecen en una regla deberán escribirse exactamente como se indica.

Valores y tipos:

Constantes y Variables

Identificadores
AND, ARRAY, BEGIN, BY, CASE, CONST, DEFINITION, DIV, DO, ELSE, ELSIF, END, EXIT, EXPORT, FOR, FROM, IF, IMPLEMENTATION, IMPORT, IN, LOOP, MOD, MODULE, NOT, OF, OR, POINTER, PROCEDURE, QUALIFIES, RECORD, REPEAT, RETURN, SET, THEN, TO, TYPE, UNTIL, VAR, WHILE, WITH.

Identificadores predefinidos

Constantes:
Declaración_de_constantes ::= CONST Asociación_constante;

Asociación_constante ::= Identificador = Expresión_constante;

Variables:
Declaracion de variables:
Declaración_de_variables ::= VAR {Lista_de_variables;
Lista_de_variables ::= Lista_de_identificadores : Tipo
Lista_de_identificadores ::= Identificador {, Identificador}
Tipo ::= INTEGER | CARDINAL | REAL | CHAR

Sentencia de asignación
Sentencia_de_asignación ::= Variable := Expresión
Variable ::= Identificador

Operaciones de lectura simple
Los datos a leer se suministran externamente en forma de texto, es decir, como una serie de caracteres seguidos que pueden incluir saltos de línea de vez en cuando. El salto de línea corresponde a la tecla marcada intro.

ReadInt;

ReadCard;

ReadReal;

Read;

Metodologia de Desarrollo de Programas I

Desarrollar programas por refinamientos sucesivos

Esta técnica es parte de las recomendaciones de una metodología general de desarrollo de programas denominada programación estructurada.

Esta técnica consiste en expresar inicialmente el programa a desarrollar como una acción global, que si es necesario se ira descomponiendo en acciones mas sencillas hasta llegar a acciones simples que pueden ser expresadas directamente como sentencias del lenguaje de programación.

Desarrollo de un esquema secuencial:

Metodología de desarrollo de un esquema de selección

Un esquema de selección consiste en plantear una acción compuesta como la realización de una acción entre varias posibles, dependiendo de ciertas condiciones, es decir, se trata de elegir para realizar una sola entre varias posibles alternativas.

Hay que hacer:

Metodología de desarrollo de un esquema de iteración

Una iteración o bucle consiste en la repetición de una acción o grupo de acciones hasta conseguir el resultado deseado. Para desarrollar un esquema de iteración dentro de un programa deberemos identificar cada uno de sus elementos componentes. Al hacerlo hay que identificar simultáneamente las variables adecuadas para almacenar la información necesaria.

Aspectos de estilo:
El estilo de redacción del programa en su forma final es algo fundamental para conseguir que sea claro y fácilmente comprensible por parte de quienes hayan de leerlo.

Encolumnado:

Comentarios:

Estructuras Basicas de la Programacion Imperativa

Programación estructurada:

La programación estructura es una metodología de programación que trata fundamentalmente de construir programas que sean fácilmente comprensibles.

Esta metodología esta basada en la técnica de desarrollo de programas por refinamientos sucesivos.

La estructura de los programas imperativas se representan tradicionalmente mediante diagramas de flujo (flow-chart)

Secuencia

Selección

Iteración

Estructuras anidadas

Expresiones Condicionales

Nivel de Prioridad da las distintas operaciones

Las operaciones se evaluan en el orden en que estan escritas en la expresion, de izquierda a derecha.

  1. Operador de Negación: NOT
  2. Operador Multiplicativo: {*} / DIV MOD AND &
  3. Operador Aditivo: + - OR
  4. Operador de Comparación: < > = >= <= <> #

Las reglas BNF

Expresión ::= Expresión_simple [Operador_comparador Expresión_simple]

Expresión_simple ::= [ + | - ] Termino {Operador_sumador Termino}

Termino ::= Factor { Operador_multiplicador Factor }

Factor ::= Identificador_de_Variable | Identificador_de_Constante | Valor_Constante | (Expresión) | NOT Factor

Operador_comparador ::= < | > | = | <= | >= | <> | #

Operador_sumador ::= + | - | OR

Operador_multiplicador ::= * | / | DIV | MOD | AND | &

Estructuras básicas en Modula-2
Secuencia

Sentencia IF

Sentencia WHILE

Sentencia FOR

Metodologia de Desarrollo de Programas II

Desarrollar programas por refinamientos sucesivos

Esta técnica es parte de las recomendaciones de una metodología general de desarrollo de programas denominada programación estructurada.

Esta técnica consiste en expresar inicialmente el programa a desarrollar como una acción global, que si es necesario se ira descomponiendo en acciones mas sencillas hasta llegar a acciones simples que pueden ser expresadas directamente como sentencias del lenguaje de programación.

Desarrollo de un esquema secuencial:

Para desarrollar una acción compuesta según un esquema secuencial se necesitara:

Metodología de desarrollo de un esquema de selección

Un esquema de selección consiste en plantear una acción compuesta como la realización de una acción entre varias posibles, dependiendo de ciertas condiciones, es decir, se trata de elegir para realizar una sola entre varias posibles alternativas.

Hay que hacer:

Metodología de desarrollo de un esquema de iteración:

Una iteración o bucle consiste en la repetición de una acción o grupo de acciones hasta conseguir el resultado deseado. Para desarrollar un esquema de iteración dentro de un programa deberemos identificar cada uno de sus elementos componentes. Al hacerlo hay que identificar simultáneamente las variables adecuadas para almacenar la información necesaria.

Ejemplos de desarrollo de programas
Un programa es correcto si produce siempre resultados de acuerdo con la especificación del programa. Evidentemente, solo tiene sentido hablar de corrección si antes de escribir el programa se ha escrito de manera precisa la especificación del comportamiento que se espera que tenga.

La única manera de verificar con seguridad la corrección de un programa es demostrar formalmente que el programa cumple con sus especificaciones.

Corrección parcial y total:

La base de la comprobación de corrección parcial es:

Razonamiento sobre sentencias de asignación:

Eficiencia de programas. Complejidad Algorítmica

Medidas de eficiencia
El tiempo que tarda en ejecutarse un programa. La cantidad de memoria usada para almacenar datos

Análisis de programas:
La determinación de la eficiencia de un programa se hace analizando los siguiente elementos

Con el criterio del numero de instrucciones ejecutadas de los esquemas básicos de los programas es el siguiente:

Funciones y Procedimientos

Concepto de subprograma
Un subprograma es una parte de un programa. Es una parte de un programa que se desarrolla por separado y se utiliza invocándolo mediante un nombre simbólico

Se emplea

La técnica de refinamientos sucesivos sugiere descomponer las operaciones complejas de un programa en otras mas simples. En sucesivos pasos de refinamiento, cada operación se vuelve a descomponer hasta que todo el programa se puede escribir utilizando sentencias disponibles en el lenguaje empleado.

Funciones
Una función es un tipo de subprograma que calcula como resultado un valor simple y único a partir de otros valores dados como argumentos.

En líneas generales, una función se asemeja bastante a la idea matemática de función con argumentos.

Definición de funciones:

Es frecuente que los lenguajes de programación utilicen la palabra PROCEDURE para designar procedimientos, y la palabra FUNCTION para designar funciones. MODULA-2 es un caso especial, y utiliza la palabra PROCEDURE para designar cualquiera de las dos clases de subprogramas.

Estas cabeceras representan la interfaz entre la definición de la función y su utilización posterior. Los nombres de los argumentos son formales, esto quiere decir, que no son variables del programa, sino solo nombres simbólicos que sirven para formalizar la definición posterior de la función, permitiendo hacer referencia a los argumentos en la definición de los cálculos.

Estas cabeceras representan la interfaz entre la definición de la función y su utilización posterior. Los nombres de los argumentos son formales, esto quiere decir que no son variables del programa, sino solo nombres simbólicos que sirven para formalizar la definición posterior de la función, permitiendo hacer referencia a los argumentos en la definición de los cálculos.

La definición completa de una función se compone de la cabecera, seguida de un cuerpo que tiene la misma estructura que un bloque de programa completo. Este bloque comienza con una parte declarativa y continua con una parte ejecutiva introducida con la palabra clave BEGIN. En la parte declarativa se declaran las constantes y variable para el uso local de la función. La parte ejecutiva estará constituida por una secuencia de sentencias. La función finalizara con la palabra clave END y a continuación nuevamente el nombre de la función seguida de un punto y coma ( ; )

En las sentencias que constituyen la función se puede y se debe hacer uso de los argumentos formales declarados en su interfaz. Esto permite parametrizar los cálculos de la función para valores particulares de los argumentos.

Ej:

PROCEDURE Potencia(x: REAL; n: CARDINAL ): REAL;
VAR k : CARDINAL;
p : REAL;
BEGIN

p := 1.0;

FOR k:= 1 TO n DO

p := p * x

END;
RETURN p
END Potencia;

Se observa que hay una nueva sentencia, iniciada con la palabra clave RETURN. Esta sentencia devuelve como valor de la función el resultado de los cálculos realizados, provoca la finalización inmediata de la ejecución de la función el resultado de la expresión debe ser un valor del tipo indicado en la declaración de la función. Dicho valor es el que se devuelve como resultado de la función.

Estructura:
RETURN Expresión.

Uso de funciones:
Para usar una función en los cálculos de un programa se invoca dicha función escribiendo su nombre y a continuación, entre paréntesis, los valores concretos de los argumentos, separados por comas.

Esta invocación de la función representa un valor del tipo de la función, que podrá ser usado como operando en una expresión aritmética o en cualquier parte del programa en que sea valido escribir una expresión de ese tipo.

Al invocar una función es obligatorio que los valores suministrados para los argumentos correspondan en numero y tipo con los argumentos en la definición. La correspondencia de tipo significa que el tipo del argumento en la invocación sea compatible en asignación con el tipo de argumento formal.

El efecto de la invocación de una función puede describirse en forma simplificada de la siguiente manera

Se evalúan las expresiones de los valores de los argumentos

Funciones predefinidas

En los argumentos simbólicos, X representa un valor numérico, C un carácter, y T un tipo.

Funciones estándar
Las funciones definidas en módulos estándar se denominan funciones estándar y pueden ser utilizadas sin necesidad de escribir su definición, pero hay que indicar expresamente que se van a utilizar dichas funciones mediante una declaración IMPORT del modulo que las contenga.

Todas estas funciones tienen un argumento REAL y devuelven un valor REAL, excepto entier, que devuelve un valor INTEGER.

Procedimientos:
Un procedimiento es un subprograma que realiza una determinada acción. A diferencia de las funciones, un procedimiento no tiene como objetivo devolver un valor obtenido por calculo.

Un procedimiento es una forma de subprograma que agrupa una sentencia o grupo de sentencias que realizan una acción, y permiten darles un nombre por el que se puedan identificar posteriormente.

Estas sentencias se pueden parametrizar mediante una serie de argumentos.

Definición de procedimientos:
La diferencia principal entre procedimiento y función es que no se declara el tipo de valor del resultado, ya que no existe.

En la definición de un procedimiento pueden usarse también sentencias de retorno, pero con un significado algo diferente que en el caso de las funciones. RETURN. Ahora se escribe sin ninguna expresión que lo acompañe, ya que no tiene que devolver ningún valor.


PROCEDURE EscribirResultado;
BEGIN
IF resultado < 0 THEN

WriteString ( Problema no resuelto);

RETURN
END;

WriteString (Resultado: );
WriteReal (resultado, 10);

END EscribirResultado;

Uso de procedimientos:

Procedimientos predefinidos:

Los procedimientos EXCL y INCL se comentaran en el tema dedicado al manejo de los conjuntos. El resto tienen la utilidad que se indica. Aquí es también aplicable el comentario hecho acerca de las funciones predefinidas, en cuanto a que los procedimientos predefinidos son en realidad seudoprocedimientos que forman parte del lenguaje en si.

Procedimientos estándar

Paso de Argumentos:
La manera fundamental de comunicar información entre las sentencias de un subprograma y el programa que lo utiliza es mediante argumentos. Hay 2 formas:

Visibilidad. Estructura de bloques:
Un subprograma se define de la misma forma que un programa completo, y puede contener declaración de constantes, variables y otros subprogramas.

Dichos elementos tienen un sentido local, de manera que no son accesibles desde el exterior del bloque.

La utilización de las variables globales es otra manera en que un subprograma puede producir resultado, asignando valores directamente a cualquiera de las variables del programa principal que lo utiliza.

Problemas de uso
Redefinición de elementos

El empleo de elementos diferentes con el mismo nombre aumenta la complejidad del programa y se dificulta mucho su comprensión. Además, se abre una vía de errores no detectables en compilación. Aunque se pretenda utilizar un símbolo como local, si se olvida su redefinición, se asumirá incorrectamente el significado dado como símbolo externo. Por tanto, salvo que sea imprescindible no se debe utilizar la redefinición de elementos.

Efectos secundarios
Cuando un subprograma modifica alguna variable eterna, se dice que esta produciendo efecto secundarios o laterales. El uso de subprogramas con efectos secundarios debe hacerse con precaución.

Para utilizar el subprograma solo se necesita conocer su interfaz y a partir de ella establecer los posibles resultados que se pueden producir. Cuando un subprograma produce efectos secundarios, esta incumpliendo el compromiso establecido en su interfaz. Esto dificulta la compresión del subprograma y puede producir resultados inesperados.

Solo si el numero de argumentos necesarios en un subprograma es muy grande o en situaciones que requieran el paso en los argumentos de grandes cantidades de datos esta justificado la utilización de efectos secundarios.

Si un subprograma produce efectos secundarios, estos deben indicarse explícitamente en los comentarios de su cabecera.

Se entiende por funcionalidad la cualidad que poseen aquellos subprogramas que permiten asegurar que siempre que se llamen con los mismos argumentos producirán exactamente los mismos resultados. Esto se logra evitando la utilización de efectos secundarios. Esa cualidad también se denomina transparencia referencial.

Doble referencia:
Se produce este efecto cuando un mismo elemento se referencia con dos nombres distinto. Puede ocurrir:

Metodologia de Desarrollo de Programas III

Operaciones abstractas
Una abstracción es una visión simplificada de una cierta entidad, de la que solo consideramos sus elementos esenciales, prescindiendo en lo posible de los detalles. Las entidades que podemos abstraer para materializarlas como subprogramas son operaciones. Con la palabra operación englobamos tanto la idea de acción como la de función.

Especificación y realización
Hay que definir 2 posibles visiones.

Resumiendo:

La forma simplificada de especificación indica solamente cual ha de ser la sintaxis o forma de uso de la operación. La especificación completa debe establecer también cual es la semántica o significado de la operación.

Funciones. Argumentos
La idea de función surge al aplicar el concepto de una abstracción a las expresiones aritméticas. Una expresión representa un nuevo valor obtenido por calculo a partir de ciertos valores ya conocidos que se usan como operandos.

El concepto matemático de función es una aplicación entre conjuntos, cuyo computo se limita a suministrar un resultado, son modificar el valor de los argumentos.

La transparencia referencial se garantiza si la realización de la función no utiliza datos exteriores a ella. Es decir, si no emplea

Esta restricciones se cumplen en el ejemplo anterior del calculo del cubo de un numero. Las funciones que cumplen la cualidad de transparencia referencial y que no producen efectos laterales o secundarios se denominan funciones puras

Acciones abstractas. Procedimientos
Un procedimiento representa una acción, que se define por separa y que se invoca por su nombre.

Al definir procedimientos no podemos limitarnos a usar solo el paso de argumentos por valor. En programación imperativa las acciones consisten habitualmente en modificar los valores de determinadas variables. Por esta razón se considera normal que los procedimientos usen argumentos pasados por referencia.

Los procedimientos se escriben siempre como procedimientos puros, entendiendo por ello que no produzcan efectos laterales o secundarios. Con esto se consigue que la acción que realiza un procedimiento se deduzca en forma inmediata de la invocación de dicha acción.

Un procedimiento cumple esta cualidad si su realización no utiliza:

Desarrollo por refinamiento usando abstracciones
Desarrollo descendente
Es simplemente el desarrollo por refinamientos sucesivos, teniendo en cuenta además la posibilidad de definir operaciones abstractas.

Considerar la operación como operación terminal, y codificarla mediante sentencias del lenguaje de programación

Considerar la operación como operación compleja, y descomponerla en otras mas sencillas.

Considerar la operación como operación abstracta, y especificarla, escribiendo mas adelante el subprograma que la realiza.

En general resultara ventajoso refinar una operación como operación abstracta, que se define en forma separada, si se consigue alguna de las ventajas siguientes:

La llamada al subprograma representa una acción adicional que consume un cierto tiempo de ejecución.

Reutilización
La realización de ciertas operaciones como subprogramas independientes facilita la reutilización de software.

La escritura de otros programas que utilicen esa misma operación resulta mas sencilla, ya que se aprovecha el código de su definición que ya estaba escrito.

Para aplicar de manera eficaz esta técnica, es preciso pensar en las posibles aplicaciones de un cierto subprograma en el momento de especificarlo, con independencia de las necesidades particulares del programa que se esta desarrollando en ese momento.

Esto tiene ventajas e inconvenientes:

Desarrollo ascendente
Esta metodología consiste en ir creando subprogramas que realicen operaciones significativas de utilidad para el programa que se intenta construir, hasta que finalmente sea posible escribir el programa principal, de manera relativamente sencilla, apoyándose en los subprogramas desarrollados hasta ese momento.

Programas robustos
La corrección de un programa exige que los resultados sean los esperados, siempre que el programa se ejecute con unos datos de entrada aceptables.

Un programa se dice que es robusto si su operación se mantiene en condiciones controladas aunque se le suministren datos erróneos.

Programación a la defensiva
Consiste en que cada programa o subprograma este escrito de manera que desconfíe sistemáticamente de los datos o argumentos con que se le invoca, y devuelva siempre como resultado:

La mejora de la robustez del programa tiene como contrapartida una cierta perdida de eficiencia, al tener que hacer comprobaciones adicionales.

Tratamiento de excepciones
Ante la posibilidad de errores en los datos con que se opera, hay que considerar dos actividades diferentes:

Definicion de Tipos

Definición de tipos

Mediante la definición de tipos de datos se consigue que cada información que maneja el computador tenga su sentido especifico. El tipo establece los posibles valores que puede tomar ese dato. La definición de tipos supone crear un nuevo nivel de abstracción dentro del programa.

En Modula-2 la declaración se realiza junto a la declaración de las constantes y variables, dentro de la 'parte_declarativa' de cualquier Bloque. Esta declaración se inicia con la palabra lave TYPE.
TYPE TipoEdad = INTEGER; TipoSexo = CHAR;

Cada tipo se define mediante un nombre o identificador seguido del símbolo igual (=), y a continuación la descripción concreta del tipo que se quiere definir. Las diferentes definiciones de tipos se separan mediante punto y coma (Eye-wink. En la definición de un nuevo tipo puede utilizar y normalmente utiliza otras tipos ya definidos. De manera formal, la sintaxis y la ubicación de la declaración de tipos:


Bloque ::= Parte_declarativa Parte_ejecutiva END Parte_declarativa::={Declaración} Declaración ::= Declaración_de_constantes | Declaración_de_tipos
| Declaración_de_variables | Declaración_subprograma

Declaración_de_tipos ::= TYPE {Definición_de_tipo ;}
Definición_de_tipo ::= Identificador =Esquema_de_tipo Esquema_de_tipo ::= Identificador_de_tipo | Tipo_enumerado | Tipo_subrango | Tipo_conjunto

Tipos enumerados
Definición de tipos enumerados
Una manera de definir un nuevo tipo de dato es enumerar todos los posibles valores que puede tomar. Se realiza mediante una lista separada por comas (,) y entre paréntesis. Cada posible valor se describe mediante un identificador. Estos identificadores al mismo tiempo quedan declarados como valores constantes. La enumeración implica un orden que se establece entre los valores enumerados. este orden se define de forma implícita e impone que el primer elemento de l lista ocupa el lugar 0 hasta el ultimo que ocupa el N-1. ( N = numero de elementos enumerados). Los tipos de datos enumerados forman parte de una clase de tipos de MODULA-2 denominados tipos ordinales, a la cual pertenecen también los tipos INTEGER, CARDINAL y CHAR, pero no el tipo REAL.

Tipo_enumerado ::= (Lista_de_identificadores) Lista_de_identificadores ::= Identificador {, Identificador}

Uso de tipos enumerados
Los tipos enumerados se emplean de manera similar a los tipos predefinidos. Los identificadores de tipo se puede emplear para definir variables de ese tipo y los identificadores de los valores se emplean como las constantes con nombre. Puesto que entre los valores enumerados existe un orden definido, podemos emplear con ellos los operadores de comparación. Al igual que para el resto de los ordinales, podemos utilizar la función predefinida ORD para obtener la posición en la lista de valores del tipo. La operación inversa, se consigue mediante la función VAL (T, N) y devuelve el valor que ocupa la posición N en la colección de valores del tipo T. Otras operaciones aplicables corresponden a procedimientos predefinidos INC y DEC, que reemplazan un valor por el siguiente o anterior.

Tipo predefinido Boolean
TYPE BOOLEAN = (FLASE, TRUE) ORD (FALSE) = 0 ORD (TRUE) =
1

Es posible realizar operaciones lógicas entre operandos booleanos (variables o no)
Operador Operación Lógica AND Conjunción OR Disyunción NOT
Negación

Es bastante habitual definir funciones cuyo resulta es un valor booleano, cuando se quiere realizar un test sobre argumentos de la función se le llama predicas: ODD (2) = FALSE ODD (7 )= TRUE

Tipo subrango
Definición de tipos subrango
Un tipo de subrango se define a partir de otro tipo ordinal ya definido, que se toma como tipo base. La forma de realizar esto
es declarar un identificador diferente para el nuevo tipo y establecer los limites mínimo y máximo del subrango de variación. Sobre el tipo real no es posible definir ningún subrango, debido a que no es tipo ordinal.

Tipo_Subrango := [Identificador_de_tipo][Limite_inferior .. Limite_superior]
Limite_inferior ::= Expresión_constante Limite_superior ::= Expresión_constante

Uso de tipos subrango
Las variables de un tipo subrango tienen la misma consideración
que las variables tipo base. La ventaja principal que ofrecen el tipo de subrango es que, previamente a cualquier asignación a una variable, se puede comprobar automáticamente que el valor a asignar esta dentro de los limites declarados, si dicho valor esta fuera, el programa finaliza con error.

Tipos estructurados
Todos los tipos de datos presentados hasta ahora se denominan escalares y son datos simples, en el sentido de que no se pueden descomponer. Un tipo estructurado de datos es un tipo cuyos valores se construyen agrupando datos de otros tipos mas sencillos Los elementos de información que integran un valor estructurado se denominan componentes.

Ampliacion de las Estructuras de Control

Estructuras complementarias de iteración
Sentencia REPEAT
Resulta adecuado emplear este esquema cuando solo son validos unos valores concretos para una determinada respuesta.

REPEAT
sentencias
UNTIL condición;

LOOP y EXIT
Indica que se ejecute siempre de forma repetitiva e incondicional la serie de sentencias


LOOP
sentencias
END;
EXIT

La sentencia EXIT es incondicional, es decir, no contiene en si misma el examen de ninguna condición.

Una sentencia EXIT SOLO se puede usar dentro de otra tipo LOOP y se produce un error de compilación cuando se trata de usar fuera de LOOP.

Estructuras complementarias de selección
Sentencia CASE


CASE valor OF
valor1 : accion1 |
valor2 : accion2 |
ELSE acción por defecto
END;

Formaciones

Necesidad de las formaciones
Facilita la ordenación de diversos datos. Las formaciones permiten la generalización de la declaración, referencia y manipulación de datos del mismo tipo.

Vectores

Declaración de vectores: TipoVector = ARRAY TipoIndice OF TipoElemento

Operaciones con vectores

Formaciones anidadas. Matrices
Declaración de matrices:
TipoMatriz = ARRAY TipoIndice1, TipoIndice2,... OF TipoElemento

Operaciones con matrices

Esquemas típicos de operación
Recorrido
Consiste en realizar la misma operación con todos y cada uno de los elementos de una formación Se emplean estructuras de tipo FOR Las variables utilizadas como indices de los FOR deben ser de los mismos TipoIndice utilizados en la declaración de la formación y su rango de variación será desde un valor extremo al otro del rango de la misma declaración

Búsqueda secuencial
El recorrido se debe detener en cuanto se encuentre el elemento buscado y solo será completo cuando no se encuentre el elemento buscando dentro de la formación Se emplean estructuras WHILE.

Esquema general:

Iniciar Búsqueda
WHILE (NOT encontrado) AND (NOT final)
DO
Pasar al siguiente elemento;
Verificar encuentro;
END

Cuando se sabe que el vector tiene al menos un elemento, es posible emplear la sentencia REPEAT, también se puede utilizar la secuencia LOOP

Inserción
Una operación de inserción de un nuevo elemento en una formación supone desplazar algunos de sus datos actuales para conseguir el hueco que le corresponde al nuevo elemento y después insertarlo en el hueco

Posible esquema:

Iniciar Inserción
WHILE (NOT hueco_encontrado) AND (NOT final)
DO
Desplazar elemento;
Pasar al siguiente elemento;
END;
Insertar nuevo elemento

Ordenación por inserción directa
Este modo consiste en insertar el elemento extraído en su lugar correspondiente entre los elementos ya ordenados Se repite con todos los vectores hasta quedar ordenado todo el vector

Búsqueda por dicotomía
Consiste en buscar un elemento en 2 mitades La búsqueda finaliza cuando el elemento se encuentra o bien cuando no es ninguno de los 2 datos consecutivos a los que queda reducida la comparación después de sucesivas divisiones en mitades.

Simplificación de las condiciones de contorno
Matrices orladas: Matrices que se dimensionan con 2 filas y 2 columnas mas de las necesarias

Vector de caracteres: Ristra
Las ristras son vectores de caracteres: ARRAY [0..n] OF CHAR: considerado como ristra o string.

Características peculiares de las ristras:

Argumentos de tipo vector abierto
Una forma de trabajar con vectores de diferentes tamaños es definir un tipo único con capacidad para el mayor de todos los que se necesiten

Cuando no se utiliza todo el tamaño, es necesario indicar de alguna forma que elementos se están empleando realmente.

Esto se puede hacer marcando el final con un valor nulo como sucede con las ristras (despilfarra memoria). La solución es emplear vectores abiertos.

Vector abierto: Es aquel del que solo se define el tipo de sus elementos, pero no el rango del indice. El tipo implícito de su indice es siempre un subrango comprendido entre 0 y 1, valor máximo.

PROCEDURE Muestra (X: ARRAY OF TipoElemento)

Registros

El esquema de tupla

Los tipos registro

Definición de registro
RECORD nombre: TIPO;
nombre: TIPO;
END

Define un campo o elemento componente. Puede usarse para definir el tipo de registro como un tipo con nombre o descripción del tipo de una variable.

Uso de registros

La sentencia WITH
Formato

WITH registro DO
secuencia_de_sentencias
END;

En la secuencia de sentencias se puede hacer referencia a los campos del registro escribiendo solo su nombre.
Las sentencias WITH pueden anidarse. Al hacerlo hay que tener en cuenta que su los registros tienen campos con los mismos nombres, se presenta una situación de ambigüedad.

Estructuras combinadas
Se pueden definir estructuras cuyas componentes son a su vez estructuras, sin limite de complejidad de los esquemas de datos resultantes.

Formas de Combinacion

El esquema unión
A veces es deseable que el tipo de un dato varíe según las circunstancias. Si las posibilidades son finitas podremos decir que el tipo de dato corresponde a un esquema que es la unión de los tipos particulares posibles.

tipo_unión = variante | variante2 | variante3 ...

Podemos aplicar los esquemas de unión a

Registros con variantes

Los esquemas de unión pueden utilizarse en Modula-2 definiéndolos como registros con variantes.

Un registro con variante tiene unos campos fijos mas una colección de variantes, cada una de las cuales consiste en un grupo particular de campos.

Para almacenar explícitamente la información de la variante concreta que se esta usando utilizamos un campo fijo discriminante (TAG)

Definición de registros con variantes

RECORD
campos_fijos
CASE discriminante : tipo OF
valor : variante |
valor : variante |
...
ELSE
variante
END;
END;

Uso de registros con variantes
Los registros con variantes se utilizan de la misma manera que los registros sin variantes.

La forma de hacer referencia al campo discriminante o a los campos de las variantes es igual que para los campos fijos.

Resumen de reglas para registro
Definición de registro

Tipo_Registro::= RECORD Secuencia_de_lista_de_campos END

Secuencia_de_lista_de_campos ::= Lista_de_campos {Lista_de_campos}

Lista_de_campos::= [Lista_de_verificadores:Esquema_de_tipo
| parte_variante]

parte_variante::= CASE [identificador :] Identificador_de_tipo OF variante {| variante}
[ELSE secuencia_de_listas_de_campos]
END

variante::= Lista_de_valores: Secuencia_de_listas_de_campos

Referencias a variables o componentes

Variable::= (Identificador_de_variable | identificador_de_campo)
{. Identificador_de_campo| [Lista_de_expresiones]}

Esquemas de datos y esquemas de acciones

  • Tupla - secuencia: colección de elementos de tipos diferentes, combinados en un orden fijo
  • Unión - selección: Selección de un elemento entre varios posibles, de tipos diferentes. Formación
  • Iteración: colección de elementos del mismo tipo.

Estructuras No Acotadas: Ficheros y Variables

Estructuras de datos no acotadas

Disponemos de estructuras de datos que no tuvieran un tamaño fijado de antemano, sino que pudieran ir creciendo o reduciendo su tamaño en función de los datos particulares que se estén manejando en cada ejecución del programa.

Estas estructuras de datos se denominan estructuras dinámicas y poseen la cualidad de que su tamaño es potencialmente ilimitado, aunque no podrá exceder la capacidad física del PC.

La estructura secuencia
Puede definirse como un esquema de datos del tipo iteración, pero con un numero variable de componentes.
Es parecida a una formación con numero variable de elementos.

Existen distintas alternativas

  • Operaciones de acceso
    • Acceso secuencial: Componentes son tratadas 1 por 1 en el orden que aparecen en la secuencia.
    • Acceso directo: Se puede acceder a cualquier componente directamente indicando su posición, como en una formación o vector.
  • Operaciones de construcción: Podemos modificar u obtener
    el valor de las componentes que existen en un momento.

    • Añadir o retirar componente al principio de la secuencia
    • Añadir o retirar componente al final de la secuencia
    • Añadir o retirar componente en posiciones intermedias de la secuencia
  • Cuando el acceso es secuencial, el tratamiento de una secuencia se realiza empleando un cursor.
  • Cursos: Variable que señala a un elemento de la secuencia.
    Para actuar sobre se plantean las siguientes operaciones:

    • Iniciar: Cursor señala el primer elemento
    • Avanzar: Cursos pasa a señalar siguiente elemento
    • Fin: Función que indica si el cursor ha llegado al final de la secuencia.

Variables dinámicas
Una variable dinámica no se declara como tal, sino que se crea en el momento necesario y se destruye cuando no se necesita

No tienen nombre, sino que se designan mediante otras variables
llamadas puntero o referencias.

Punteros

  • Son variables simples cuyo contenido es precisamente una
    referencia a otra variable

  • Usaremos una flecha para representarla.
  • Los punteros están tipados. El tipo de un puntero especifica en realidad el tipo de variable a la que puede apuntar.
    TYPE tipo_puntero = POINTER TO Tipo_de_variable;

  • Una variable puntero se usa para designar la variable apuntada: puntero^
  • Para detectar si un puntero señala realmente o no a otra variable, existe el valor NIL que es compatible con cualquier tipo de puntero e indica que el puntero no señala a ninguna parte.

Uso de variables dinámicas

  • Una variable de un programa se corresponde con un a pequeña zona de memoria que el compilador reserva para almacenar el valor
  • Las variables normales de un programa tienen esa zona de memoria reservada al empezar a ejecutarse el programa o subprograma en que se declara
  • Las variables declaradas en un subprograma solo existen mientras se ejecutan las sentencias de un subprograma.
  • La forma mas sencilla de crear una variable dinámica es la operación: NEW (puntero)
  • Una variable dinámica puede estar referenciada por mas de un puntero
  • Cuando una variable dinámica no es necesaria se puede liberar el espacio que ocupaba, se utiliza: DISPOSE (puntero)
  • Los procedimientos que realmente están disponibles en cualquier compilador: ALLOCATE (puntero,tamaño), DEALLOCATE (puntero,tamaño)
  • Estos procedimientos no son predefinidos, están en el modulo STORAGE, debiendo hacer la importación.
  • NEW DISPOSE esta definido así
    TYPE Tipo_puntero = POINTER TO Tipo_de_dato;
    VAR pun : Tipo_puntero;
    NEW (pu) = ALLOCATE (pun,size (Tipo_dato))
    DISPOSE (pun) = DEALLOCATE (pun, size(Tipo_dato))

Realización de secuencias mediante punteros
Al utilizar los punteros, debes tener cuidado y emplearlo
de manera precisa, traduciendo a punteros los mecanismos de definición de alto nivel que deberían estar disponibles.

Una definición recursiva es aquella en que se hace referencia
a si misma.

Operaciones con secuencias enlazadas
Describimos la manera de realizar algunas operaciones típicas sobre secuencias enlazadas con punteros

Recorrido: El recorrido de toda secuencia se consigue mediante un bucle de acceso a elementos y avance del cursor

Como la secuencia tiene un numero indefinido de elementos, no se usara un bucle con contador.

Cursor := secuencia;(*iniciar cursor*)
WHILE cursor <> NIL DO (* NOT fin*)
WriteInt (cursor^.valor,10)
cursor := cursor^.siguiente(* avanzar cursor *)
END

Datos persistentes

Son aquellos que conservan su valor entre ejecuciones sucesivas de los programas que operan con ellos.

Intervienen la memoria interna y la externa (CD´s, Diskettes,...)

Este tipo de datos esta ligado a las operaciones de entrada y salida de información

Para manejar datos persistentes hay que declarar variables en las que serán copiados temporalmente (durante el funcionamiento del programa) y ademas se necesitan operaciones adicionales para establecer la conexión entre dichas variables en memoria interna y los datos en memoria externa.

Ficheros
La forma clásica de usar datos persistentes es mediante el
empleo de ficheros

Los ficheros son estructuras de datos en memoria externa,
que pueden ser manipulados desde un programa, estableciendo una conexión entre dichos ficheros en memoria externa y las variables fichero definidas por el programa en memoria interna.

  • Abrir: Establece la asociación entre una variable fichero
    interna y fichero externo, designado mediante un nombre.}}

  • Cerrar: Elimina la conexión anterior, garantizando que los
    datos almacenados en la memoria externa quedan debidamente actualizados.

Los ficheros son estructuras de datos no acotadas, que pueden
almacenar tanta información como se desee, dentro de la capacidad real disponible en cada soporte.

Los mas sencillos son un esquema de datos del tipo secuencia

Un sistema de ficheros permite tener almacenados en un mismo soporte diferentes ficheros que se reparte entre ellos la capacidad de almacenamiento disponibles.

Cada fichero ocupa en un momento dado el espacio que necesita, en funciona de la cantidad de información que contiene, ya que los ficheros son estructuras dinámicas de datos

Los nombres de los distintos ficheros han de ser usados como parámetros en las operaciones de apertura de ficheros.

Ficheros secuenciales
Son estructuras de tipo secuencia:

  • Acceso a los elementos ha de ser secuencial
  • El fichero ha de ser usado en uno de dos modos: Lectura o escritura
  • En modo lectura se usa la información contenida en el fichero, sin modificarlo
  • En modo escritura el fichero se graba desde el comienzo. La información anterior se pierde.

Si es necesario modificar parte del fichero, hay que generar
otro nuevo con la información actualizada a partir del antiguo.

Si el proceso termina con éxito puedes borrar el antiguo y quedarte con el nuevo

Los ficheros de entrada y salida principales son manejados por el modulo estándar InOut.

Cada fichero se utiliza mediante un curso implícito, que se maneja indirectamente mediante los procedimientos de lectura y escritura.

Operaciones básicas:

  • Iniciar cursor: Se realiza automáticamente al comienzo del programa, al tiempo que se abre un fichero. Solo se hace una vez.
  • Avanzar: Se realiza con los procedimientos READ y WRITE, al tiempo que se toma el siguiente carácter de la secuencia de entrada o se añade el siguiente carácter a la secuencia de salida.
  • Fin: No existe esta función como tal, en su lugar hay una variable DONE que puede ser consultada tras cada operación de lectura, y que indica si dicha lectura se realizo con éxito o no se pudo realizar por encontrarse el cursor al final de la secuencia de entrada.

El modulo InOut permite cambiar durante la ejecución del programa los ficheros asignados como entrada y salida principales.

Para ello existen unos procedimientos predefinidos llamados 'OpenInput' y 'OpenOutput', que provocan la lectura por el terminal de los nombres de los ficheros correspondientes.

También existen los procedimientos 'Closeinput' y 'CloseOutput'
que finalizan el trabajo con dichos ficheros y vuelven a emplear la entrada y salida principal establecida al comienzo del programa.

Ficheros de texto
Es en realidad un fichero secuencial de caracteres

La única diferencia esta en el modelo lógico de esa secuencia
de caracteres, que se considera dividida en lineas de texto, separadas unas de otras por caracteres especiales de fin de linea.

La organización del texto en lineas permite estructurar los datos de entrara y salida, aprovechando los separadores de lineas para marcar la separación de los grupos de datos.

Para detectar los cambios de linea en el fichero de entrada del modulo InOut exporta una constante EOL (End Of line) de tipo carácter.

Si el carácter leído es igual a 'EOL' es que se ha saltado de linea

Lectura y escritura con conversión
Los ficheros de texto son el medio principal de combinación
entre el usuario y la maquina aplicamos este termino a cualquier medio de entrada o salida de secuencias de caracteres, incluyendo los terminales con pantalla y teclado...

La ventaja de los ficheros de texto es que prácticamente cualquier elemento de información puede representarse en forma legible mediante ristras de caracteres.

La lectura o escritura de estos valores a partir de ficheros de texto exige la conversión entre el valor interno, en el código de la maquina y su representación externa en forma de secuencia de caracteres.

Los procedimientos de lectura standard ReadInt', 'ReadCard'
y 'ReadReal'. Tienen el siguiente comportamiento:

  • Al comenzar la lectura, se ignoran los caracteres de espacio en blanco que se vayan leyendo inicialmente.
  • A continuación se leen tantos caracteres como sea posible hasta encontrar algún espacio en blanco o salto de linea. Este carácter terminal queda ya leído, de manera que las operaciones de lectura que se ejecutan a continuación no lo volverán a leer. Los caracteres leídos se convierten a valor numérico.
  • Si los primeros caracteres no blancos que se encuentran no constituyen una representación valida de un valor numerico, el valor devuelto es arbitrario, y se asigna falso a la variable global 'DONE' exportada por el modulo InOut.
  • Para evitar perder información en el caso de que el carácter que termina la lectura sea significativo, el modulo InOut exporta una variable global TERMCH, en que queda almacenado dicho carácter de terminación al finalizar la operación de lectura (la lectura de valores reales puede no actualizar esta variable)

Estas operaciones no son procedimientos predefinidos

Ficheros de acceso directo
Se denominan ficheros de acceso directo aquellos en que se puede acceder directamente a un elemento de información contenido en el fichero, sin necesidad de acceder a los anteriores.

Existen varios modelos lógicos diferentes de ficheros de acceso directo:

  • Ficheros con organización relativa: Se especifica la componente a la que se accede mediante su posición relativa en el fichero.
  • Ficheros indexado: Se especifica la componente mediante el valor de un campo clave contenido en ella.

Solo estudiamos ficheros con organización relativa, también llamados 'Ficheros de acceso directo'

Las características de las operaciones desde acceso son:

  • Se puede acceder directamente a una componente del fichero conociendo su posición relativa
  • El fichero puede ser usado simultáneamente en lectura y en escritura
  • Una operación de lectura obtiene la información contenida en una componente de la secuencia, sin modificarla.
  • Una operación de escritura permite grabar un nuevo valor en una componente de la secuencia, o añadir una nueva componente al final
  • Se puede truncar el fichero, eliminando las componentes finales, a partir de una cierta posición.

El manejo de ficheros de acceso directo en Modula-2 no esta del todo normalizado. Existe un modulo estándar llamado FileSystem, que contiene las operaciones adecuadas para estos ficheros.

Modulos

Concepto de módulo

Un modulo es un fragmento de programa independiente utilizado en algún momento para la construcción del programa completo.

Un modulo debería ser compilado por separado. La razón se debe a la necesidad de limitar la complejidad de aquello que esta siendo elaborado por una persona en un momento dado.

El concepto de modula esta ligado a la idea de abstracción. Un modulo debe definir un elemento abstracto y debe ser usado desde fuera con solo saber que hace el modulo pero sin saber como lo hace.

Especificación y realización
La especificación de un modulo que contenga la definición de una serie de elementos abstractos consiste en el conjunto de las
especificaciones de cada uno de ellos mas una indicación de los posibles efectos de unos sobre otros cuando se usan en forma combinada.

Es todo lo necesario para poder usar los elementos definidos en el. Constituye el interface entre el modulo y el programa que lo usa.

La realización del modulo consiste en la realización de cada
uno de los elementos abstractos contenidos en dicho modulo.

La independencia entre la realización de un modulo y el programa
que lo usa se incrementa si la realización de un elemento abstracto no es visible desde donde se usa. Esta característica se denomina ocultación (mecanismo de visibilidad de los bloques)

  • Compilación separada: El programa esta formado por varios ficheros fuente, cada uno de los cuales se compila por separado
  • Compilación segura: Al compilar un fichero fuente el compilador comprueba que el uso de elementos de otros módulos es consistente con la interfaz.
  • Ocultación: Al compilar un fichero fuente el compilador no usa información de los detalles de realización de elementos de otros módulos

Técnicas empleadas por lenguajes de programación reales

  • El fichero del programa y del modulo se tratan en forma totalmente separada, sin visibilidad de la interfaz (FORTRAN, y C) [No hay compilación segura]
  • La parte necesaria de la interfaz se copia manualmente en el programa que la usa. La compilación de los ficheros del programa y del modulo se hace con total independencia (C ANSI, PASCAL) [Mayor seguridad en compilación pero hay posibilidad de errores]
  • La interfaz del modulo y su realización se escriben en ficheros separados. El mismo fichero de interfaz se usa tanto al compilar la realización del modulo como al compilar el programa que lo usa (Modula-2, ADA) [Compilación completamente segura]

Descomposición modular
Esta descomposición permite trabajar a distintos programadores en el mismo programa.

El objetivo de la ingeniería de software es facilitar el desarrollo de la aplicación en forma organizada. Para que la descomposición en módulos sea adecuada, los módulos tienen que ser completamente independientes. Esta independencia se analiza según el acoplamiento y cohesión.

  • El acoplamiento entre módulos indica cuantos elementos distintos o características de uno o varios módulos han de ser tenidos en cuenta al usar un modulo desde otro. Este acoplamiento debe reducirse al mínimo.
  • La cohesión indica el grado de relación que existe entre
    los distintos elementos de un mismo modulo, y debe ser lo mayor posible.

Módulos en Modula-2
Modulo principal
La ejecución del programa equivale a ejecutar este modulo.
A partir de este, se pueden importar los demás módulos.

Módulos de definición
La especificación de un modulo se escribe como modulo de definición:

DEFINITION MODULE Nombre;
...lista de importaciones...
...definiciones...
END Nombre.

Las listas de importaciones se escriben igual que para el modulo principal.

Las definiciones pueden incluir definiciones de constantes, tipos y variables, también pueden incluir especificaciones de subprogramas.

Una especificación de subprograma consistirá en la cabecera de la función o procedimiento.

La lista de exportación solo se emplea en versión antiguas de Modula-2, en las versiones actuales, todos los elementos del modulo de definición se exportan implícitamente.

Módulos de implementación
Contienen la realización del modulo.

IMPLEMENTATION MODULE Nombre;
...lista de importaciones...
...definiciones...
BEGIN
...sentencias de inicializacion...
END Nombre.

Las sentencias ejecutables que figuran al final del modulo son opcionales. Estas sentencias se ejecutan automáticamente al comienzo de la aplicación, antes de que se ejecute el programa principal, y antes de que se ejecute la inicialización de cualquier otro modulo que utilice este modulo.

Según la jerarquía de módulos reflejada en el diagrama de estructura de una aplicación, comprobamos que se ejecutan estrictamente de abajo a arriba, empleando por inicializar los módulos que no usan a ningún otro, luego los que usan estos, y terminando por ejecutar el modulo principal.

Uso de módulos
Los elementos definido en un modulo se pueden usar desde otro. Para ello hay que importarlos. La importación se realiza al comienzo del programa o modulo que desea usarlos.

Formas para importar

  • FROM nombre_de_modulo IMPORT lista_de_nombres;
  • IMPORT nombre_de_modulo;
  • nombre_de_modulo.nombre_de_elemento

Tipos abstractos de datos
Un enfoque mas moderno de la programación trata de asociar la idea de tipo de datos con la clase de valores, abstractos, que
pueden tomar los datos.

Los valores de los tipos enumerados no son valores numéricos, ni ristras de caracteres, aunque pueden transformarse en esas otras formas.

En este enfoque, llegamos a la idea de tipos abstractos, esto quiere decir que un programa que use ese tipo de datos no debería necesitar ningún cambio por el hecho de modificar la representación o codificación de los valores de ese tipo. Si analizamos con cuidado que necesita un programa para poder usar datos de un tipo, encontraremos que hace falta:

  • Hacer referencia al tipo en si, mediante un nombre, para
    poder definir variables, subprogramas,...

  • Hacer referencia a algunos valores particulares, generalmente como constantes con nombre.
  • Invocar operaciones de manipulación de los valores de ese
    tipo, usando operadores en expresiones aritméticas o subprogramas.

El conjunto de todos estos elementos constituye el tipo abstracto de datos (Agrupación de una colección de valores y una colección de operaciones de manipulación)

Desarrollo modular basado en abstracciones
Abstracciones para desarrollo modular
Las abstracciones se llaman abstracciones funcionales, con independencia de que sean una función propiamente dicha o bien un procedimiento que realiza una acción.

El mecanismo de módulos permite ampliar el repertorio de abstracciones, a las que se les denominan abstracciones de datos y por demos distinguir, los tipos abstractos de datos y los datos abstractos (encapsulados)

Desarrollo por refinamiento basado en abstracciones

La única novedad que se introducen ara son las abstracciones
de datos y la posibilidad de desarrollar también las abstracciones funcionales como módulos separados.

Reutilización de módulos

Se suele considerar que la descomposición modular basada en abstracciones es una buena metodología para desarrollar módulos
que van a ser reutilizados en el futuro.

Los módulos que definen abstracciones relacionadas entre si pueden agruparse en una biblioteca que se pone a disposición de quienes desarrollan aplicaciones en un campo determinado.