Sei sulla pagina 1di 15

7. 7.1. 7.2. 7.3. 7.3.1. 7.3.2. 7.3.3. 7.3.4. 7.3.5. 7.3.6. 7.4. 7.5. 7.6. 7.6.1. 7.6.2. 7.6.3.

7.6.4. 7.7. 7.8. 7.9.

TIPOS DE DATOS ................................................................................................................................................................ 2 TIPOS DE DATOS E INFORMACIN DE TIPOS ................................................................................................................... 2 TIPOS SIMPLES............................................................................................................................................................... 3 CONSTRUCTORES DE TIPO ............................................................................................................................................. 4 PRODUCTO CARTESIANO ............................................................................................................................................... 4 UNIN ............................................................................................................................................................................ 5 SUBCONJUNTOS ............................................................................................................................................................ 6 ARREGLOS Y FUNCIONES ............................................................................................................................................... 6 TIPOS APUNTADOR Y RECURSIVO .................................................................................................................................. 7 TIPOS DE DATOS Y EL ENTORNO .................................................................................................................................... 8 NOMENCLATURA DE TIPOS EN LENGUAJES DE EJEMPLO............................................................................................... 8 EQUIVALENCIA DE TIPOS................................................................................................................................................ 9 VERIFICACIN DE TIPOS ............................................................................................................................................... 10 COMPATIBILIDAD DE TIPOS .......................................................................................................................................... 11 TIPOS IMPLCITOS ........................................................................................................................................................ 12 TIPOS QUE SE SUPERPONEN Y VALORES DE TIPOS MLTIPLES ................................................................................... 12 OPERACIONES COMPARTIDAS ..................................................................................................................................... 12 CONVERSIN DE TIPOS ................................................................................................................................................ 12 VERIFICACIN DE TIPOS POLIMRFICOS ...................................................................................................................... 13 POLIMORFISMO EXPLCITO ........................................................................................................................................... 15

7. Tipos de datos
Todo programa utiliza datos, ya sea de manera implcita o explcita, para llegar a un resultado. Los datos en un programa se renen en estructuras de datos, que se manipulan mediante estructuras de control que representan algoritmos. algoritmos + estructuras de datos = programas Los datos en su forma ms primitiva en el interior de la computadora son simplemente una coleccin de bits. La mayora de los lenguajes incluyen un conjunto de entidades simples de datos, como enteros, reales y booleanos, as como mecanismos para construir nuevos tipos a partir de los mismos. Estas abstracciones contribuyen prcticamente a todas las metas del diseo de lenguajes como: legibilidad, capacidad de escritura, confiabilidad e independencia de la mquina. Sin embargo estas abstracciones pueden conllevar una serie de problemas como son: o Dependencia de la mquina: Un ejemplo de lo anterior es lo finito de todos los datos en una computadora, lo cual queda enmascarado por las abstracciones. o Precisin de los nmeros y operaciones aritmticas con reales. o La falta de consenso entre los diseadores de lenguajes en relacin al grado de informacin de tipos que debe de hacerse explcita para verificar la correccin del programa antes de la ejecucin. o Existen muchas razones para tener alguna forma de verificacin de tipos esttica (en tiempo de traduccin): La informacin de tipos estticos permite a los compiladores asignar memoria con eficiencia y generar cdigo mquina que manipula los datos eficientemente, mejorando la eficiencia de la ejecucin. Un compilador puede utilizar los tipos estticos a fin de reducir la cantidad de cdigo que necesita compilar, mejorando la eficiencia de traduccin. La verificacin de tipos estticos permite que muchos errores estndar de programacin sean detectados rpidamente, lo que mejora la capacidad de escritura. La verificacin de tipos estticos mejora la seguridad y la confiabilidad de un programa al reducir la cantidad de errores de ejecucin que pueden ocurrir. Los tipos explcitos mejoran la legibilidad al documentar el diseo de los datos. Pueden utilizarse los tipos explcitos para eliminar ambigedades en los programas. Los programadores pueden utilizar los tipos explcitos combinados con la verificacin de tipos estticos como una herramienta de diseo, de manera que las decisiones errneas de diseo se pongan de manifiesto en forma de errores en tiempo de traduccin. La tipificacin esttica de interfaces mejora el desarrollo de los programas grandes al verificar la consistencia y correccin de la interfaz.

7.1. Tipos de datos e informacin de tipos


Los datos en los programas pueden clasificarse de acuerdo con sus tipos. Todo valor de datos expresable en un LP tiene implcito un tipo (por ejemplo, en C el valor -1 es de tipo entero, el 3,2334 es de tipo double...). Un tipo de datos es un conjunto de valores, junto con un conjunto de operaciones sobre dichos valores y con ciertas propiedades. Un intrprete de lenguaje puede utilizar el conjunto de propiedades algebraicas de una variedad de maneras para asegurarse de que los datos y las operaciones se utilizan de manera correcta en un programa.
z = x / y;

El interprete puede determinar si x e y tienen los mismos tipos y si dicho tipo tiene un operador de divisin definido para sus valores. El proceso por el cual pasa un intrprete para determinar si la informacin de tipos en un programa es consistente se conoce como verificacin de tipos. El proceso de asignar tipos a expresiones (x / y) se conoce como inferencia de tipos. Este proceso puede considerarse como una operacin por separado y llevarse a cabo durante la verificacin de tipos o considerarse como parte de la verificacin de tipos misma.
2
Longinos Recuero Bustos (http://longinox.blogspot.com)

Todo lenguaje ofrece una diversidad de maneras para construir tipos ms complejos, basndose en los tipos bsicos (int, char, double), estos mecanismos se conocen como constructores de tipo, y los tipos creados se conocen como tipos definidos por el usuario. Los nuevos tipos creados con constructores de tipo no tienen automticamente un nombre y se les denomina tipo annimo, sin embargo, los nombres son de extrema importancia (documentacin de cdigo, verificacin de tipos, ).
int a[ 10 ]; // Crea en C una variable cuyo tipo "arreglo de int" annimo

Los nombres para los nuevos tipos se crean utilizandos una declaracin de tipos (a veces definicin de tipos).
// Definicin de un nuevo tipo typedef int Array_of_ten_integers[ 10 ]; // Asignacin del nuevo tipo Array_of_ten_integers a;

Cada lenguaje con declaraciones de tipo tienen reglas para ello, y estas se conocen como algoritmos de equivalencia de tipo. Los mtodos utilizados para la construccin de tipos, el algoritmo de equivalencia de tipos y las reglas de inferencia y de correccin de tipos, se conocen de manera colectiva como un sistema de tipos. Si en un lenguaje, todos los errores de tipo se detectan en tiempo de traduccin, se dice que es un lenguaje fuertemente tipificado. Un tipificado fuerte asegura que la mayora de los programas peligrosos (programas con errores que corrompen datos) se rechazarn en tiempo de traduccin, y aquellos que no se rechacen, causarn un error antes de cualquier corrupcin de datos. Ada, ML, Haskell, Modula son lenguajes fuertemente tipificado. C se le conoce como un lenguaje dbilmente tipificado. Los lenguajes sin sistemas de tipificacin esttica se conocen como lenguajes sin tipificacin (o lenguajes con tipificacin dinmica). Estos lenguajes incluyen, Scheme y otros dialectos de Lisp, Smaltalk y la mayora de los lenguajes de scripts, como Perl. En un lenguaje sin tipos, toda la verificacin de seguridad se lleva a cabo en tiempo de ejecucin.

7.2. Tipos simples


Todo lenguaje contiene un conjunto de tipos predefinidos (int, char, double). Tambin a veces se predefinen variaciones sobre los tipos bsicos (short, unsigned, ). Los tipos predefinidos son principalmente tipos simples: tipos que no tienen otra estructura que su aritmtica inherente o una estructura secuencial. Sin embargo existen tipos simples que no estn predefinidos: o Los tipos enumerados: Los tipos enumerados son conjuntos cuyos elementos se denominan y se listan de manera explcita.
enum Color { Red, Green, Blue };

Las enumeraciones se definen en una declaracin de tipo y son verdaderos nuevos tipos. En la mayora de lenguajes, las enumeraciones estn ordenadas, considerando que el orden en el cual se listan los valores es importante, existiendo a menudo, una operacin sucesora o predecesora para todo tipo enumerado.

Los tipos de subrango: Son subconjuntos contiguos de tipos simples especificados al dar por lo menos el elemento menor y el ms grande.
Longinos Recuero Bustos (http://longinox.blogspot.com)

type Digit_Type is range 0..9;

Esto es til si en un programa deseamos: Distinguir este tipo de otros tipos enteros. Minimizar almacenamiento. Generar verificaciones en tiempo de ejecucin para asegurar que los valores siempre estn en el rango correcto. Estos tipos se conocen como tipos ordinales, porque existe un orden discreto en el conjunto. Todos los tipos enteros numricos son tipos ordinales y entre otras disponen de operaciones de sucesor y de predecesor. No as como los nmeros reales, por lo que una operacin de subrango es usualmente incorrecta en la mayora de lenguajes.

7.3. Constructores de tipo


Dado que los tipos de datos son conjuntos, las operaciones de conjuntos pueden utilizarse para construir nuevos tipos a partir de los existentes. Cuando se aplican estas operaciones de tipos a los tipos se les llama constructores de tipos. En un LP todos los tipos se construyen a partir de tipos predefinidos utilizando constructores de tipos.

7.3.1. Producto cartesiano


Dados los conjuntos U y V, podemos formar el producto cartesiano formado por todos los pares ordenados de elementos de U y V. En muchos lenguajes el constructor de tipos del producto cartesiano est disponible como la construccin de estructuras o de registros.
struct IntCharReal { int i; char c; double r; }

Existe una diferencia entre un producto cartesiano y una estructura de registro: o En una estructura los componentes tienen nombre, en tanto que en un producto cartesiano se hace referencia a ellos por su posicin. Las proyecciones en la estructura de registro estn dadas por la operacin de selector de componentes (o miembro de la estructura): o Si x es del tipo IntCharReal, entonces x.i es la proyeccin de x hacia enteros. La mayora de los lenguajes de programacin consideran los nombres componentes como parte del tipo definido por un registro, por lo que la siguiente estructura puede considerarse diferente de la anterior aunque representen el mismo producto cartesiano:
struct IntCharReal { int j; char ch; double d; }

Algunos lenguajes tienen una forma ms pura del tipo estructura de registro, que es en esencia idntica al producto cartesiano, donde a menudo se les denomina tuplas. Por ejemplo en ML podemos definir IntCharReal como:
Longinos Recuero Bustos (http://longinox.blogspot.com)

Type IntCharReal = int * char * real;

Un tipo de datos que se encuentra en los lenguajes orientados a objetos, que est relacionado con las estructuras, es la clase. Un esquema tpico de asignacin para los tipos de producto cartesiano es la asignacin secuencial, segn el espacio que requiere cada componente. Por ejemplo:
Type IntCharReal = int * char * real;

Requiere un espacio de 13 bytes, 4 para el int, 1 para el char y 8 para el real.

7.3.2. Unin
Se forma tomando el conjunto de unin terica de sus conjuntos de valores. Existen dos variedades de unin: o Discriminada: Si se le agrega una etiqueta o discriminador para distinguir el tipo de elemento. o Indiscriminadas: No tienen etiqueta y debe suponerse el tipo de cualquier valor en particular. En C y C++ el constructor de tipo union proporciona uniones indiscriminadas:
union IntOrReal { int i; double r; };

Al igual que con struct, existen nombres para diferenciar los distintos componentes (i y r). Los nombres son necesarios porque comunican al intrprete el tipo con el que deben interpretarse los bits dentro de la unin. Estos nombres no deben de confundirse con los discriminantes, que es un componente separado que indica el tipo de datos que es realmente el valor, a diferencia del tipo que puede pensar que es:
Imitacin de un discriminante
enum Disc {IsInt, IsReal}; struct IntOrReal { enum Disc which; union { int i; double r; } val; }; IntOrReal x; x.which = IsReal; x.val.r = 2.3; ... if(x.which == IsInt) printf("%d\n", s.val.i); else printf("%g\n", x.val.r);

Uso

Las uniones pueden resultar tiles para reducir los requerimientos de asignacin de memoria para las estructuras cuando no se necesitan, simultneamente, diferentes elementos de datos. Esto se debe a que a las uniones se les asigna un espacio de memoria equivalente al mayor necesario para cada uno de sus componentes y los valores de cada componente se almacenan en regiones superpuestas de la memoria. Las uniones, sin embargo, no son necesarias en lenguajes orientados a objetos, ya que en un mejor diseo sera utilizar la herencia para representar diferentes requerimientos de datos que no se superponen.
Longinos Recuero Bustos (http://longinox.blogspot.com)

7.3.3. Subconjuntos
En matemticas se pueden definir subconjuntos al dar una regla para distinguir sus elementos, como:

En los lenguajes de programacin se puede hacer algo parecido para definir nuevos tipos que sern subconjuntos de tipos conocidos. En ocasiones los subconjuntos heredan operaciones de sus tipos padres. Una perspectiva alternativa a la relacin de subtipos es definirla en trminos de operaciones compartidas. Esto es, un tipo es subtipo de un tipo si y slo si todas las operaciones de los valores de tambin pueden aplicarse a valores del tipo . La herencia en los lenguajes orientados a objetos se puede considerar como un mecanismo de subtipo, en el mismo sentido de compartir operaciones.

7.3.4. Arreglos y funciones


El conjunto de todas las funciones:

puede dar lugar a un nuevo tipo de dos formas como un tipo: o Arreglo. o Funcin. Cuando es un ordinal, la funcin puede considerarse como un arreglo con un tipo de ndice y tipo de componente . En C, C++ y Java el conjunto de ndices siempre es un rango de enteros positivos que comienzan por 0. Los arreglos pueden definirse con o sin tamao, pero para definir una variable de tipo arreglo hay que asignarle un tamao ya que los arreglos son asignados estticamente o en la pila. C puede definir arreglos y variables de arreglo de la siguiente manera:
const int Size = 5; // Defienicin de tipos typedef int TenIntArray[ 10 ]; typedef int IntArray[]; // Definicin de variables TenIntArray x; int y[ 5 ]; int z[] = { 1, 2, 3, 4, 5 }; IntArray w = { 1, 2 }; // IntArray w; /* Incorrecto!! */ // int x[ Size ]; /* Incorrecto en C!!, correctoe n C++ */

C permite que arreglos sin tamao especificado sean parmetros de funciones:


int array_max( int a[], int size ) { int tem, i; assert( size > 0 ); temp = a[ 0 ]; for( i = 1; i < size; i++ ) { if( a[ i ] > temp) temp = a[ i ]; } return temp; };

Longinos Recuero Bustos (http://longinox.blogspot.com)

En C y C++ el tamao del arreglo no forma parte del mismo, por eso en el ejemplo anterior el tamao del arreglo tuvo que ser pasado como un parmetro adicional (int size). Java si puede asignar arreglos de forma dinmica (en el montn) y su tamao puede especificarse en forma totalmente dinmica. Dicho tamao constituye una parte de la informacin almacenada cuando se asigna el arreglo (length). Los arreglos multidimensionales tambin son posibles, declarndolos como arreglos de arreglos. Los arreglos probablemente son los constructores ms utilizados ya que su implementacin puede hacerse en forma muy eficiente. Los lenguajes funcionales por lo general no contienen un tipo arreglo ya que estos estn pensados para la programacin imperativa. Usualmente los lenguajes funcionales utilizan listas en vez de arreglos. Algunos lenguajes pueden crear tipos generales de funcin y procedimiento.
// Definicin de un tipo de funcin de enteros a enteros typedef int( *IntFunction )( int ); // Este tipo puede definir variables o parmetros int square( int x ) { return x + x; } // Def. varaiable IntFunction f = square; // Def. parmetro int evaluate( IntFunction g, int value ) { return g( value ); }

La mayora de los lenguajes orientados a objetos, como Java y Smalltalk, no tienen variables o parmetros de funcin, debido a que estn enfocados a los objetos en vez de a funciones.

7.3.5. Tipos apuntador y recursivo


Un constructor de tipos que no corresponde a una operacin de conjuntos es constructor de referencias o apuntadores, que construye el conjunto de todas las direcciones que se refieren a un tipo especificado. En C, una declaracin que construye el tipo de todas las direcciones en que haya enteros almacenados sera:
typedef int* IntPtr;

Los apuntadores estn implcitos en lenguajes que tienen administracin automtica de memoria. Este es el caso de Java, para el cual todos los objetos son apuntadores implcitos que se asignan de forma explcita (new) pero son desasignados automticamente por un recolector de basura. A veces los lenguajes hacen distincin entre referencias y apuntadores, definiendo como referencia la direccin de un objeto bajo el control del sistema, que no se puede utilizar como valor ni operar de forma alguna, no as con los apuntadores. En este sentido los apuntadores en Java en realidad son referencias. Tal vez C++ es el nico lenguaje donde coexisten apuntadores y referencias. En C++ los tipos de referencia se crean con un operador postfijo & (lo cual no debe confundirse con el operador prefijo de direccin &, que devuelve un apuntador):
Longinos Recuero Bustos (http://longinox.blogspot.com)

double r = 2.3; double& s = r; // s es una referencia a r, as comparten memoria s += 1; // ahora tanto r como s valen 3.3

Las referencias en C++ son en esencia apuntadores constantes que se desreferencian cada vez que se usan. En C y C++, los arreglos son implcitamente apuntadores constantes hacia su primer componente.
int a[] = { 1, 2, 3, 4, 5 }; int* p = a; printf( printf( printf( printf( "%d\n", "%d\n", "%d\n", "%d\n", *p *( *( 2[ ); // imprime p + 2 ) ); // imprime a + 2 ) ); // imprime a ] ); // imprime 1 3 3 3 que que que que es es es es el el el el valor valor valor valor de de de de a[ a[ a[ a[ 0 2 2 2 ] ] ] ]

Los apuntadores son de gran utilidad en la creacin de tipos recursivos (un tipo que se utiliza as mismo en su declaracin). Estos tipos tienen una gran importancia en las estructuras de datos y algoritmos, ya que corresponden naturalmente a los algoritmos recursivos y representan datos cuya estructura y tamao no se conocen de antemano. Dos ejemplos tpicos son las listas y los rboles. En C se permiten declaraciones recursivas indirectas por medio de apuntadores:
struct CharListNode { char data; struct CharListNode* next; }; typedef struct CharListNode* CharList; CharList cl = ( CharList )malloc( sizeof( struct CharListNode ) ); ( *cl ).data = 'a'; // expresin equivalente: cl->data = 'a'; ( *cl ).next = 0; // expresin equivalente: cl->data = 0;

7.3.6. Tipos de datos y el entorno


Vase captulo 8.

7.4. Nomenclatura de tipos en lenguajes de ejemplo


C: o Los tipos simples se conocen como tipos bsicos, y los que se construyen mediante constructores de tipos se conocen como derivados. Los tipos bsicos incluyen el void (cuyo conjunto de valores est vaco) y los tipos numricos: los tipos enteros (ordinales) y los tipos flotantes.

Java: o Los tipos simples se llaman tipos primitivos, y los que se construyen utilizando constructores de tipos se llaman tipos de referencia. o Los tipos primitivos se dividen en el tipo boolean y tipos de punto flotante (cinco enteros y dos en coma flotante).
8
Longinos Recuero Bustos (http://longinox.blogspot.com)

Slo existen tres constructores de tipos: el arreglo, la clase y la interface.

Ada: o Los tipos simples se llaman tipos escalares. o Los tipos ordinales se llaman discretos, los tipos numricos comprenden los tipos reales y enteros. o Los tipos apuntador se llaman tipos access. o Los tipos de arreglo y de registro se llaman tipos compuestos.

7.5. Equivalencia de tipos


En qu casos dos tipos son iguales? Una manera de responder a esta pregunta es comparar los conjuntos de valores simplemente como conjuntos. Dos conjuntos son iguales si contienen los mismos valores. Dos de las formas ms habituales de equivalencia de tipos en los lenguajes de programacin actuales son: o Equivalencia estructural: Dos tipos son iguales si tienen la misma estructura, es decir, estn construidos de la misma forma a partir de los mismos tipos simples y en el mismo orden y con los mismo nombres de variables internas. Es fcil de implementar y aporta toda la informacin necesaria para llevar a cabo la verificacin de errores y asignacin de almacenamiento. Para verificar la equivalencia estructural, un intrprete puede representar los tipos como rboles y verificar la equivalencia recursivamente en subrboles. A continuacin se exponen dos equivalencias estructurales, siempre y cuando el tamao del conjunto ndice no es parte del tipo arreglo:
typedef int A1[ 10 ]; typedef int A1[ 20 ];

Un factor que complica las cosas es el uso de nombres de tipo en las declaraciones:
struct RecA { char x; int y; }; struct RecB { char x; int y; };
Longinos Recuero Bustos (http://longinox.blogspot.com)

Ambas declaraciones deberan ser estructuralmente equivalentes, sin embargo no lo son, ya que las variables de las diferentes estructuras tendran que usar diferentes nombres para acceder a los datos de los miembros. Para determinar la equivalencia estructural en presencia de nombres, basta con reemplazar en la declaracin cada nombre por la expresin asociada a su tipo, excepto en el caso de tipos recursivos, en donde esta regla llevara a un ciclo infinito. Las razones principales para incluir nombres de tipos es permitir la declaracin de tipos recursivos.

Equivalencia de nombres: Dos tipos son iguales slo si tienen el mismo nombre y dos variables son equivalentes en tipo solo si sus declaraciones usan exactamente el mismo nombre de tipo.. La equivalencia de nombres en su estado ms puro es incluso ms fcil de implementar que la estructural, siempre y cuando estemos obligados a dar nombre a todos los tipos. Ada es un lenguaje que ha implementado una equivalencia de nombres muy pura. C tiene una equivalencia que est entre la estructural y la de nombres y se puede decir que tiene una equivalencia de nombre para struct, union y estructural para todo lo dems. En el siguiente fragmento de cdigo en C:
struct RecA { char x; int y; }; // Definicin de un nuevo tipo. typedef struct RecA RecA; struct RecA a; RecA b; struct RecA c; struct { char x; int y; }d; a, b, c y d son equivalentes estructuralmente, pero las nicas equivalentes en nombres son a y c.

Java tiene un mtodo relativamente simple para la equivalencia de tipos: o Primero, no existe typedef, por lo que se minimizan los problemas con nombres. o Segundo, las declaraciones class e interface crean implcitamente nuevos nombres de tipos y para estos tipos se utiliza la equivalencia de nombres. o La nica complicacin es que los arreglos emplean equivalencia estructural con reglas especiales para establecer la equivalencia del tipo base.

7.6. Verificacin de tipos


La verificacin de tipos es el proceso que sigue el interprete para verificar que todas la construcciones en un programa tengan sentido en trminos de los tipos de constantes, variables, procedimientos y otras entidades. Involucra la aplicacin del algoritmo de verificacin de tipos a expresiones y declaraciones, pudiendo este modificar el uso del algoritmo de equivalencias para adecuarse al contexto. La verificacin de datos puede dividirse en verificacin: o Dinmica: Si la informacin de tipos se conserva y se verifica en tiempos de ejecucin. Por definicin lo interpretes realizan verificacin dinmica de los tipos.

10

Longinos Recuero Bustos (http://longinox.blogspot.com)

Los compiladores tambin pueden generar cdigo que conserve los atributos del tipo durante el tiempo de ejecucin en una tabla o como etiquetas en un entorno. La verificacin dinmica de los tipos es necesaria cuando los tipos slo pueden determinarse en tiempo de ejecucin.

Esttica: Los tipos de expresiones y de objetos se extraen del texto del programa y el intrprete lleva a cabo la verificacin de tipos antes de la ejecucin.

Ejemplo 1: Los compiladores de C efectan una verificacin esttica durante la traduccin, pero realmente C no es un lenguaje con tipificado fuerte y que muchas inconsistencias en los tipos no causan errores de compilacin. Ejemplo 2: El dialecto Scheme de Lisp es un lenguaje con tipificado dinmico, pero los tipos se verifican en forma rigurosa. Todos los errores de tipo provocan la terminacin del programa. Ejemplo 3: Ada es un lenguaje con tipificado fuerte y todos los errores de tipo generan mensaje de error en la compilacin, pero sin embargo, incluso en Ada, ciertos errores, como los de rango en subndice de arreglos, no pueden detectarse antes de la ejecucin. Una parte esencial en la verificacin de tipos es la inferencia de tipos, en la cual los tipos de expresiones se infieren a partir de los tipos de las subexpresiones que la componen. Las reglas de verificacin de tipos y las reglas de inferencia a menudo estn entremezcladas: Por ejemplo, una expresin pueden determinarse como de tipo correcto, si y son del mismo tipo y este tipo contiene una operacin (verificacin de tipos) y el tipo de la expresin resultante es del tipos de y (inferencia de tipos). Las reglas de verificacin y de inferencia de tipos tienen una estrecha relacin con el algoritmo de equivalencia de tipos:
void p( struct{ int i; double r; } x ) { ... }

La declaracin de anterior es un error, segn el algoritmo de equivalencia de tipos de C, ya que ningn parmetro real puede tener el tipo del parmetro formal x. La inferencia de tipos y las reglas de correccin a menudo son las partes ms complejas en la semntica de un lenguaje.

7.6.1. Compatibilidad de tipos


o o o o A menudo resulta til relajar las reglas de correccin de tipos de manera que los tipos de componentes no sean precisamente iguales, segn el algoritmo de equivalencia de tipos. Dos tipos diferentes que incluso pueden ser correctos cuando se combinan en ciertas formas se conocen como tipos compatibles. Un trmino relacionado, la compatibilidad de asignacin, a menudo se utiliza para la correccin de tipos de la asignacin . Inicialmente puede parecer que este enunciado es del tipos correcto cuando ambos componentes son del mismo tipo, pero esto ignora una diferencia importante, el lado izquierdo debe ser un valor o referencia l, y el lado derecho debe ser un valor r. Igual que con la compatibilidad ordinaria, la compatibilidad de asignacin pude ampliarse para casos en los que ambos lados son de diferente tipo. En C y en Java, todos los tipos numricos son compatibles y las conversiones se llevan a cabo de forma que se conserva tanta informacin como sea posible.

o o

11

Longinos Recuero Bustos (http://longinox.blogspot.com)

7.6.2. Tipos implcitos


o o o o Los tipos de las entidades bsicas como las constantes o las variables pueden no establecerse explcitamente en una declaracin. En estos casos el intrprete debe de inferir el tipo, ya sea a travs del contexto o a partir de alguna regla estndar. Estos tipos se conocen como implcitos. En todos los lenguajes los literales son el ejemplo ms claro de entidades tipificadas implcitamente.

7.6.3. Tipos que se superponen y valores de tipos mltiples


o o o Los tipos pueden superponerse cuando dos tipos contienen valores en comn. Es preferible que los tipos sean conjuntos no conexos, evitando as ambigedades al determinar el tipo de un valor. Imponer esta restriccin de forma arbitraria sera demasiado limitante, eliminando una de las caractersticas principales de la POO, la capacidad de crear subtipos mediante la herencia que refina los tipos existentes, al tiempo que conservan su pertenencia en el tipo ms general. Sin embargo, en ocasiones los tipos que se superponen y los valores de tipos mltiples pueden representar un beneficio directo para simplificar el cdigo. Por ejemplo, en C, el literal 0 no solo es un valor de todos los tipos enteros, sino tambin representa el apuntador nulo.

7.6.4. Operaciones compartidas


o o o o Los tipos tienen operaciones asociadas que usualmente estn definidas de forma implcita. A menudo estas operaciones son compartidas entre varios tipos, o tienen el mismo nombre que otras operaciones que pueden ser diferentes. Se considera que estos operadores estn sobrecargados ya que se utiliza el mismo nombre para operaciones que en esencia son diferentes. En el caso de un operador sobrecargado, el intrprete debe decidir, a partir de los tipos de los operandos, a que operacin se refiere.

7.7. Conversin de tipos


En todos los lenguajes de programacin existe la necesidad, bajo ciertas circunstancias, de convertir un tipo a otro. Esta conversin de tipos puede incorporarse al sistema de tipos, de forma que las conversiones se lleven a cabo de forma automtica.
int x = 3; ... x = 2.3 + x / 2;

En este ejemplo, el intrprete insert dos conversiones automticas o conversiones implcitas: o La conversin del resultado int a double en la operacin x / 2. o La conversin del resultado double a int en la operacin 2.3 + 1.0. Conversiones implcitas como esta se conocen como coacciones. La conversin de int a double es el resultado de una conversin de extensin. La conversin de double a int es el resultado de una conversin de restriccin (puede involucrar perdida de datos). La conversin implcita puede debilitar la verificacin de tipos de forma que no se detecten errores, poniendo en peligro el tipificado fuerte y la confiabilidad del LP. Una alternativa a la conversin implcita es la conversin explcita, presentndose cuando las directrices de la conversin se escriben directamente en el cdigo, tambin llamada conversin forzada. Existen dos variantes de sintaxis para la conversin forzada:
12
Longinos Recuero Bustos (http://longinox.blogspot.com)

La primera es utilizada en C y en Java:


x = ( int )( 2.3 + ( double )( x / 2 ) );

La segunda es utilizad por C++ y Ada y se le conoce como sintaxis de llamado de funciones:
x = int( 2.3 + double( x / 2 ) );

o o

La ventaja de utilizar conversiones forzadas es la de documentan en forma precisa dentro del cdigo, existiendo menor probabilidad de comportamientos inesperados. Adems, la eliminacin de las conversiones implcitas facilita al intrprete resolver la sobrecarga:
double max( int, double ); double max( double, int ); ... double x = max( 2, 3 ); // Qu funcin se ejecutar?

Una alternativa a las conversiones forzadas es tener funciones predefinidas o de biblioteca, que lleven a cabo dichas conversiones. Como ejemplo, en Java la clase Integer en la biblioteca java.lang contiene las funciones de conversin toString, que convierte un int en un String, y parseInt que convierte un String en un int.
String s = Integer.toString( 1234 ); int i = Integer.parseInt( "54321" );

En algunos lenguajes est prohibida la conversin implcita a favor de la explcita, la cual favorece la documentacin de la conversin minimizando los riesgos de comportamientos extraos, facilitando la sobrecarga. Como ejemplo de estos lenguajes tenemos a Ada. Un paso intermedio es permitir la conversin implcita siempre que no involucre corrupcin de los datos, en este sentido Java slo permite conversin por extensin. Los lenguajes orientados a objetos tienen requerimientos especiales para la conversin, ya que la herencia puede interpretarse como un mecanismo de subtipificacin y en algunos casos es necesario hacer conversiones de subtipos a supertipos y viceversa.

7.8. Verificacin de tipos polimrficos


La mayora de los lenguajes de tipificado esttico exigen que en todos los nombres de cada declaracin se d informacin sobre los tipos. Sin embargo, tambin es posible aplicar una forma de inferencia de tipos para determinar los tipos de los nombres en una declaracin en la que no se hayan dado dichos tipos. Esta forma es conocida como verificacin de tipos Hindley-Milner, cuyos pasos son: o Se comienza confeccionando el rbol sintctico de la expresin. o Se llenan los tipos de los nombres (los nodos de las hojas) a partir de las declaraciones. o Si no se conocen los tipos, se asignan tipos simulados. o A partir de las declaraciones, el verificador de tipos va ascendiendo por las ramas asignando y verificando que los tipos sean correctos.
int i; int a[] = { ... }; ... a[ i ] + i;

13

Longinos Recuero Bustos (http://longinox.blogspot.com)

i; a[] = { ... }; ... a[ i ] + i;

Dos observaciones sobre esta forma de verificacin de tipos: o Una vez que una variable de tipo es reemplazada por un tipo real (o una forma ms especializada de tipo), todas las instancias de la variable deben actualizarse para coincidir con el nuevo valor de la variable tipo. Este proceso se conoce como instanciamiento de las variables tipo. o Cuando se dispone de nueva informacin sobre los tipos, las expresiones de tipos para las variables pueden cambiar de forma en diversas maneras. Este proceso se conoce como unificacin. La unificacin involucra tres casos: o 1. Cualquier variable de tipo se unifica con cualquier expresin de tipos (y es instanciado segn esa expresin) o 2. Dos constantes de tipo cualquiera (como int o double) slo se unifican si son del mismo tipo. o 3. Dos construcciones de tipo cualquiera (como arreglo o struct) slo se unifican si son aplicaciones del mismo constructor de tipo y todos sus tipos componentes tambin se unifican. Por ejemplo: o Al unificar la variable de tipo con la expresin de tipo arreglo de se produce el caso 1, y es inicializado por instancia a arreglo de . o Unificar int a int es un ejemplo del caso 2. o Al unificar arreglo de con arreglo de se produce el caso 3. La verificacin de tipos Hindley-Milner aporta una enorme ventaja en la verificacin de tipos simples, ya que los tipos pueden conservarse tan generales como sea posible, a la vez que se verifica su consistencia de forma estricta. Considerando el ejemplo:
a[ i ] = b[ i ]

Esta expresin asigna el valor de b[ i ] a a[ i ]. La verificacin de Hindley-Milner establecer que i deber ser un int, a deber ser un arreglo de y b debe ser un arreglo de , y luego, == . La verificacin de tipos concluye considerando los tipos de a y b como restringidos a arreglo de , pero sigue siendo una variable irrestricta, que podra ser de cualquier tipo. Se dice que esta clase de expresiones son polimrficas y la verificacin de tipos Hindley-Milner implementa implcitamente la verificacin de tipos polimrficos.
14
Longinos Recuero Bustos (http://longinox.blogspot.com)

El tipo arreglo de es en realidad un conjunto de tipos mltiples e infinitos, dependiendo de las posibles inicializaciones por instancias de la variable de tipo . Esta clase de polimorfismo se conoce como polimorfismo paramtrico, ya que es un parmetro de tipo que puede ser reemplazado por cualquier expresin de tipo. De esta manera podemos hablar de dos tipos de polimorfismo paramtrico: o Implcito, los parmetros de tipo son introducidos implcitamente por el verificador de tipos. o Explcito, los parmetros de tipo son introducidos explcitamente por el programador. Todo objeto de tipo polimrfico que se pasa a una funcin como parmetro debe tener una especializacin fija a lo largo de toda la funcin. Un intrprete lleva a cabo la traduccin de cdigo en el paso a una funcin con argumentos de tipos polimrficos de dos formas: o Expansin: Se examinan todas las llamadas a la funcin y se genera una copia del cdigo para cada uno de los tipos empleados usando el tamao apropiado para cada tipo. o Encuadrado y Etiquetado: Se fija un tamao para todos los datos que pueden contener valores escalares, se agrega un campo de bits que etiqueta el tipo como escalar o no, y un campo de tamao si no son escalares. Todos los tipos estructurados quedan representados por un apuntador y un tamao, mientras que los tipos escalares se copian directamente.

7.9. Polimorfismo explcito


Deseamos definir una estructura de datos que pueda contener cualquier tipo de dato. Para ello, es imposible hacer que el tipo polimrfico sea implcito; en vez de ello, debemos escribir en forma explcita mediante la sintaxis apropiada. A esto se le conoce como polimorfismo paramtrico explcito. Los tipos de datos polimrficos con parmetros explcitos funcionan muy bien en lenguajes con verificacin HindleyMilner, pero no son ms que un mecanismo para crear constructores de tipos definidos por el ususario. C++ es un ejemplo de lenguaje con polimorfismo paramtrico explicito, pero sin tener asociada la verificacin de tipos Hindley-Milner. El mecanismo para lo anterior es la plantilla (template), que puede usarse ya sea con funciones o con construcciones de tipos class o struct. Como ejemplo podemos tomar el siguiente cdigo en C++ que define una pila utilizando un parmetro de tipo explcito:

template <typename T> struct StackNode { T data; StackNode< T >* next; }; template <typename T> struct Stack { StackNode< T >* theStack; }; Stack< int > s; s.theSatck = new StackNode< int >; s.theStack->data = 3; s.theStack->next = 0;

15

Longinos Recuero Bustos (http://longinox.blogspot.com)

Potrebbero piacerti anche