You are on page 1of 31

Lección 2: Comprobación de Tipos

1. Introducción Lecturas:
2. Sistemas de tipos Scott, capítulo 7
3. Representación de tipos Aho, capítulo 6
• Expresiones de tipos Fischer, sección 10.1
• Árboles Holub, sección 6.3
4. Comprobación de tipos Bennett, capítulo 9
• Equivalencia Cooper, sección 4.2
• Conversión
• Coerción
• Inferencia
5. Perspectiva

12048 - J. Neira – Universidad de Zaragoza 1


1. Introducción
int *(*s[10])[];
int i, v[10];
...
• ¿tipo de esta declaración? v[i] = 1;
• ¿es legal?
• ¿cuánto espacio ocupa s?
var i : 1..10;
var A, B: array(1..10) i := 10;
of boolean;
A := B; j = succ(i);
• ¿es esto legal en ADA? • ¿puede detectarse estos pro-
blemas durante la compilación?
procedure p(...);
begin typedef struct {
.... q(...); ....
end; int tipo;
procedure q(...); struct nodo *izq;
begin struct nodo *der;
.... p(...); ....
end; } nodo;
• ¿cómo comprobar esta decla- • ¿cómo comprobar esta decla-
ración? ración?
12048 - J. Neira – Universidad de Zaragoza 2
Análisis Semántico
Nombres
... r = i; ...
if (r > i) goto L1 ... i = r; ...

• r, i: declaradas, • convertir i a real


• L1: aparecer una vez • convertir r a entero
int i, j, k;
loop A float r, s, t;
...
end A; k = i + j;
j = i + r;
t = r + s;
• A: aparecer al comienzo y final
(o no aparecer) • determinar qué tipo de opera-
ción llevar a cabo
Tipos
... r = i(); ...
... if (a == b) ... Lugar en el programa
break; continue;
• i: declarado como función
• valor devuelto por i com- • sólo dentro de un bucle
patible con el tipo de r goto L1;
• a y b: comparables
• sólo en el mismo bloque
12048 - J. Neira – Universidad de Zaragoza 3
Comprobación de tipos
1. Verificar que los tipos y valo- • Equivalencia:
res asociados a los objetos determina cuándo dos objetos
pueden considerarse del mismo
de un programa se utilizan de tipo.
acuerdo con la especificación
del lenguaje.
• Compatibilidad:
2. Detectar conversiones implí- determina cuándo un objeto de
citas de tipos para efectuarlas cierto tipo puede ser usado en un
o insertar el código apropiado cierto contexto.
para efectuarlas
• Inferencia:
• Almacenar información relativa derivación del tipo de un objeto a
a los tipos de los objetos partir de sus componentes.
¿representación?
¿representación?
• Conversión:
• Aplicar las reglas de verifica- permitir y efectuar un cambio de
ción de tipos tipo.
¿cómo
¿cómoyycuándo
cuándoaplicarlas?
aplicarlas? • Coerción:
conversión automática de un tipo
a otro.
12048 - J. Neira – Universidad de Zaragoza 4
2. Sistemas de tipos
1. Tipos primitivos 2. Constructores
• booleano: un byte, 0 (false), 1 • enumerados: orden total
(true)
type dia is (lun, mar,
int i = 2; mie, jue,
vie, sab,
... dom);
if (i) ...
type fs is (sab, dom);
• subrangos: intervalos
• caracter: un byte, ASCII • registros: tuplas
Java: dos bytes, UNICODE • vectores: secuencias
• entero: dos bytes...
var s: string[80];
char c; ...
int i; write(s);
short s;
long l; ... • conjuntos: selección
• punteros: referencias
• real: coma fija, coma flotante • listas: sec. sin indexado
• racionales? • ficheros: sec. con pos.
• complejos? • funciones: genera un valor

12048 - J. Neira – Universidad de Zaragoza 5


Constructores: ortogonalidad
• Cada elemento debe ser
Idealmente, los tipos deberían
independiente de los demás
ser ortogonales (hace más clara
• Deben poder usarse en la programación.)
cualquier combinación
• Todas las combinaciones
deben tener sentido Tipos :
• ¿subrangos de reales?
Sentencias (Algol):
a := if b < c then d • ¿conjuntos de caracteres?
else e; • ¿registros de registros?
...
a := begin • ¿vectores de registros?
f(b);
g(c)
end; • ¿conjuntos de reales?
...
g(c); • ¿ficheros de ficheros?
2 + 3;
• ¿vectores con índices reales?
C:
• ¿vectores con índices
if (a == b) ...
if (a = b) ... registros?

12048 - J. Neira – Universidad de Zaragoza 6


Sistemas de tipos
3. Reglas
• de equivalencia de tipos:
cuándo los tipos de dos objetos son iguales
• de compatibilidad de tipos:
cuándo puede usarse un valor en un contexto
• de inferencia de tipos:
determinar el tipo de una expresión con base en el tipo de sus
elementos

• La complejidad semántica del lenguaje depende de la variedad de


tipos primitivos y de constructores.

• La rigidez semántica depende de la flexibilidad en la aplicación de las


reglas de utilización y conversión de tipos.
• BASIC, Fortran: simples y rígidos
• C: complejo, pero poco rígido
• ADA: complejo y rígido

12048 - J. Neira – Universidad de Zaragoza 7


Según cómo y cuando se
aplican estas reglas...
Lenguajes estáticamente tipados
• Los tipos de los objetos se determinan durante la compilación. Esto
se hace a través de la declaración de todos los objetos antes de su
utilización. Ejemplos: Java y C.

Lenguajes dinámicamente tipados


• Los tipos se determinan durante la ejecución. Ejemplos: Python,
Lisp, Snobol4.

Lenguajes débilmente tipados


• El programador puede obviar, y en algunos casos ignorar, el tipo de
los objetos que maneja. Ejemplo: C

Lenguajes fuertemente tipados


• Las reglas de utilización de tipos se aplican estrictamente.
Ejemplos: Java, ADA.
12048 - J. Neira – Universidad de Zaragoza 8
Lenguajes DEBILMENTE tipados: C
• Tipos primitivos: char, int, float, double ...
• Constructores: *, [], struct, ()
• Declaración: ’specifier’ (’declarator’)*
sp decl*
int i; /* entero */
int *j; /* puntero a entero */
int *k(); /* funcion dev puntero a entero */
int (*l)(); /* puntero a funcion dev entero */
int *m[9]; /* vector de punteros a entero */
int (*n)[]; /* puntero a vector de enteros */
int *o()[]; /* !! funcion que dev vector */
int **p(); /* funcion dev pt a pt a entero */
int *q()(); /* !! funcion dev funcion */
int **r[][]; /* !! matriz de pt a pt a entero */
int *(*s[10])[];
int *(*f())();
12048 - J. Neira – Universidad de Zaragoza 9
main(int argc, char *argv[])
{
char *w[];
...
}
3: array size missing in `w'

int f(int v[][10])


{
v[1][2] = 8;
}
ok
12048 - J. Neira – Universidad de Zaragoza 10
C: lenguaje débilmente tipado
• Las funciones pueden tener un • Se permite la conversión:
número variable de parámetros:
int *i;
{ char *j;
int i, j, k, f(); ...
j = (char *) i;
j = f (i);
k = f (i, j); • Se efectúa coerción:
} float f(int i)
{
int j;
• La compatibilidad es muy amplia: ...
return j;
enum { }
lun, mar, mie, main()
jue, vie, sab, {
dom int i; char a;
} dia;
... i = 540; a = i;
dia = 4; printf ("%d\n", 540);
dia = 40; printf ("%d\n", i);
printf ("%d\n", a);
}
12048 - J. Neira – Universidad de Zaragoza 11
FUERTEMENTE tipados: ADA
• Tipos primitivos: character, • El concepto de equivalencia es
integer, boolean, float, muy restrictivo:
fixed var A, B: array(1..10)
• Constructores: array, of boolean;
record, access... ...
A := B;
• La comprobación es más sen-
• Hay conversión: cilla (está mas claro lo que hay
que hacer).
var r : float; • La sobrecarga aumenta la
i, j : integer; flexibilidad:
...
r := float (2*J); type dia is (lunes,
j := integer (1.6); martes,
i := integer (-0.4); miercoles,
jueves,
viernes,
• No hay coerción: sabado,
domingo);
if (r + 1 > 0) then
... type festivo is (sabado,
domingo);
12048 - J. Neira – Universidad de Zaragoza 12
3. Representación de Tipos
1. Para describir la estructura de un tipo en un lenguaje de programación
se puede utilizar una notación funcional llamada expresión de tipos.
C:
Una expresión de tipos es: tipo
array(componente, indice)
•Un tipo primitivo record(campo1,...,campon)
•Un constructor aplicado a pointer(tipo)
una expresión de tipos function(arg1, ..., argn, tipo)

int i; i: int
int *j; j: pointer(int)
int *k(); k: function(pointer(int))
int (*l)(); l: pointer(function(int))
int *m[9]; m: array(pointer(int),int)
int (*n)[]; n: pointer(array(int,int))
int *o()[]; o: function(array(pointer(int),int))
int **p(); p: function(pointer(pointer(int)))
int *q()(); q: function(function(pointer(int)))
int **r[][]; r?
int *(*s[10])[]; s?
12048 - J. Neira – Universidad de Zaragoza 13
Árboles de Tipos
2. Una expresión de tipo también puede describirse gráficamente como un
árbol de tipos.
– Las hojas son tipos o valores primitivos.
– Los nodos interiores son constructores.
• Ejemplo (Pascal):

var a: array[1..10] of array[1..20] of integer;

• Expresión de tipos:
a: array(array(integer,
subrange(integer,1,20)),
subrange(integer,1,10))

array
• Árbol de tipos:
array subrange

integer subrange integer 1 10

integer 1
12048 - J. Neira – Universidad de Zaragoza
20 14
Tipos en la Tabla de Símbolos
(Tabla de Atributos)
• Ejemplo (PASCAL P4): registro con campos variantes
type
IdPtr = ^Identifier;
Parte
Partefija:
fija:
Identifier = record •Nombre
•Nombre
Name: Alpha; •Inf.
Llink, Rlink: IdPrt; •Inf.de
deacceso
acceso
IdType: TypePtr; •Clase
•Clase
Next: IdPtr; •Tipo
•Tipo
case Class : IdClass of
Constant: ( Value: ValueType );
TypeName ();
Variable: ( Vkind: IdKind;
Vlevel: LevelRange;
Vaddr: AddressRange
);
Field: ( Offset: AddressRange );
Proc, Func: (
case PFDeclKind : DeclKind of
Standard: (...);
Declared: (...)
)
end;
12048 - J. Neira – Universidad de Zaragoza 15
Tipos en la Tabla de Símbolos
(Tabla de Atributos)
• Ejemplo (PASCAL P4): registro con campos variantes
TypePtr = ^TypeDescriptor
TypeDescriptor = record
Size: AddressRange;
PackedFlag: boolean;
case Form : TypeForm of
Scalar: (
Parte case ScalarKind : DeclKind of
Partevariable:
variable: Declared: ( First: IdPtr );
•Tamaño
•Tamaño Standard: ( )
•…..
•….. );
Subrange: ( SubBType: TypePtr;
Min, Max: Value
);
Pointer: ( PtrBType: TypePtr );
SetType: ( SetBType: TypePtr );
ArrayType: (
IndexType, ElementType: TypePtr
);
RecordType: ( FirstField: IdPtr );
FileType: ( FileBaseType: TypePtr )
end;
12048 - J. Neira – Universidad de Zaragoza 16
Representación de ELEMENTO
typedef struct {
char nombre[2];
¿representación? int natomico;
float patomico;
int metal;
} ELEMENTO;

• Identifier • TypeDescriptor
ELEMENTO, , ,
10, 0, RecordType,

nombre, , , , ,Field:0
2, 0, ArrayType, ,
natomico, , , , ,Field:2
2, 0, int
patomico, , , , , Field:4
1, 0, char
metal, , , -, , Field:8
4, 0, float
12048 - J. Neira – Universidad de Zaragoza 17
4. Comprobación de Tipos
• Comprobación Estática: • Comprobación Dinámica:
llevada a cabo durante la com- llevada a cabo durante la eje-
pilación cución.
– Toda la información necesaria – Programas menos eficientes
debe estar disponible (desventaja de los intérpretes).
– Programas más eficientes (no se procedure Compute is
genera código) K : Integer :=
Integer'Last;
#define I 5 begin
K := K + 1;
short i; end Compute;
char v[10];
– Referencia a variables sin valor
asignado.
i = 10*32767;
var i : integer;
... ...
write(i);
v[2*I] = ’b’; ...

... – Punteros a NULL.


var p : ^integer;
v[4] = 1000; ...
^p := 100;
...
12048 - J. Neira – Universidad de Zaragoza 18
Equivalencia
type r1 = record
• Equivalencia estructural: i : integer;
dos tipos son equivalentes si sus f : real;
componentes lo son, y están end;
organizadas de igual manera type r2 = record
• La definición exacta depende del f : real;
i : integer;
lenguaje. end;

type v1 = array[1..10]
type r1 = record of char;
i, j : integer; v2 = array[0..9]
end; of char;
type r2 = record
i : integer;
j : integer; type persona = record
end; nombre,
type r3 = record direccion : string[80];
a : integer; end;
b : integer;
end; type empresa = record
nombre,
direccion : string[80];
end;
12048 - J. Neira – Universidad de Zaragoza 19
Equivalencia estructural
• Método usual de comproba- • ¿por qué? tipos recursivos:
ción: algoritmo recursivo de
comparación de árboles. typedef struct {
int tipo;
struct nodo *izq;
• C: comprobación de tipos es- struct nodo *der;
tructural: } nodo;
{ • Árbol de tipos:
int (*f)();
int (*g)();
f = g; record
}
• ¡Excepto para registros! integer pointer pointer
struct {
int i; char c;
} a; ¡El método de comprobación
struct { debe utilizar los nombres!
int i; char c;
} b; • Expresión de tipos:
....
a = b; nodo: record(int,
pointer(nodo),
pointer(nodo))
12048 - J. Neira – Universidad de Zaragoza 20
Equivalencia
• Equivalencia Nominal: dos • Pascal: a cada definición implí-
tipos son equivalentes si tienen cita se le asigna un nombre di-
el mismo nombre ferente
type r1 : record
b : integer; var a : record
c : real; b : integer;
end;
c : real;
r2 : record end;
b : integer; d : record
c : real;
end; b : integer;
var a : r1; c : real;
d : r2; end;
...
a.b := d.b; ...
... a := d;
a := d;
• El programador diferencia los
tipos a través de los nombres: • ADA: la compatibilidad es MUY
type metros = real; restringida
millas = real;
var A, B : array(1..10)
var d : metros; l : millas; of BOOLEAN;
....
d := l; A := B;

12048 - J. Neira – Universidad de Zaragoza 21


Conversión
• El programador modifica explí- 2. Tienen diferente represen-
citamente el tipo de una expre- tación a bajo nivel (estas
sión; puede ocurrir que: operaciones pueden no ser
1. Los tipos tengan la misma reversibles)
representación a bajo nivel;
entonces es una operación Conversión en PASCAL:
puramente conceptual. var r : real;
En ADA: i : integer;
c : char;
type tt = 0..10; ..
var t : tt; i := trunc (r);
i : integer; ...
...
i := integer(t); i := ord (c);
En C (casting):
Evitar la conversión en C:
float *pr;
int *pi; float r;
... char c;
pr = (float *) pi; ...
pi = (int *) pr; c = *((char *) &r);

12048 - J. Neira – Universidad de Zaragoza 22


Coerción
• El compilador modifica el tipo • Tipos genéricos:
automáticamente.
PASCAL: typedef void *ELEMENTO;
var a : real; typedef struct nodo {
i : integer; ELEMENTO dato;
.. struct nodo *sig;
a := i; } NODO, *pNODO;
C:
float f() • A favor:
{ facilita la abstracción y extensi-
int i; bilidad de los programas, facili-
char c;
... tando la incorporación de tipos
c = i; nuevos.
return i; • En contra:
} riesgos de seguridad. Los len-
guajes modernos tienden a ale-
ADA: jarse de la coerción.
no existe
12048 - J. Neira – Universidad de Zaragoza 23
Inferencia
• Determinar el tipo de un objeto a • ML es especialmente complejo,
partir de sus componentes: el compilador siempre debe
type Ta = 0..20; inferir el tipo:
Tb = 10..20;
fun circum(r) =
var a : Ta, r * 2.0 * 3.14159;
b : Tb; ...
... circum(7)
c := a + b;
fun cuadrado(x) = x * x;
– No puede ser Ta, ni Tb.
– ¿nuevo tipo? • Provee una forma inmediata de
polimorfismo:
• PASCAL: del tipo base
fun comparar (x, p, q) =
• ADA: deriva un tipo anónimo if x = p then
+: if x = q then ”ambos”
r.min := o1.min + o2.min; else ” primero”
r.max := o1.max + o2.max; else
-: if x = q then ”segundo”
r.min := o1.min - o2.max; else ”ninguno”;
r.max := o1.max - o2.min;
12048 - J. Neira – Universidad de Zaragoza 24
5. Perspectiva
• Comprobación semántica más profunda: man lint
1 #include <stdio.h>
2 “lint attempts to detect features of
3 main () the named C program files that are
4 {
5 int i, j, k; likely to be bugs, to be non-portable,
6 char c; or to be wasteful. It also performs
7 float *r; stricter type checking than does the
8 C compiler.”
9 f (5, 4);
10 printf ("%s\n", f (5.0));
11 r = (float *) &c;
12 goto L1; (9) (10) f: variable # of args
13 i = f (0); (10) f, arg. 1 used inconsistently
14 L1: i = j; (9) f returns value which is
15 } sometimes ignored
16 (11) possible pointer alignment
17 int f (n) problem
18 int n;
19 { (20) function f has return(e);
20 if (n > 1) and return;
21 return n * f (n-1); (13) statement not reached
22 else ; (13) i set but not used
23 } (14) j may be used before set
(5) k unused in function main
12048 - J. Neira – Universidad de Zaragoza 25
5. C .vs. ADA
http://libre.act-europe.fr/Software_Matters

enum Alert_Type {LOW, MEDIUM, HIGH, VERY_HIGH};

void handle_alert (enum Alert_Type alert) {


switch (alert) {
case LOW:
activate_camera ();
case MEDIUM:
send_guard ();
case HIGH:
sound_alarm ();
}
}

void process_alerts () {
handle_alert (2);

• Compila, pero ¿tiene problemas?


12048 - J. Neira – Universidad de Zaragoza 26
5. C .vs. ADA
http://libre.act-europe.fr/Software_Matters
void handle_alert (enum
Alert_Type alert) {
• Olvidas los break switch (alert) {
case LOW:
activate_camera ();
• Olvidas algún caso break;
case MEDIUM:
importante send_guard ();
break;
case HIGH:
• 2 y High no son lo mismo sound_alarm ();
break;
case VERY_HIGH:
alert_police ();
break;
}
}
void process_alerts () {
handle_alert (HIGH);
12048 - J. Neira – Universidad de Zaragoza 27
5. C .vs. ADA
http://libre.act-europe.fr/Software_Matters

type Alert_Type is (LOW,


• ADA es más seguro MEDIUM, HIGH, VERY_HIGH);

procedure Process_Alert (Alert :


• Verifica todos los casos Alert_Type) is
begin
case Alert is
• No hace falta break when LOW =>
Activate_Camera;
when MEDIUM =>
• Solamente puedes usar el Send_Guard;
tipo Alert_type when HIGH =>
Sound_Alarm;
when VERY_HIGH =>
Alert_Police;
end case;
end Process_Alert;

12048 - J. Neira – Universidad de Zaragoza 28


5. C .vs. ADA
http://libre.act-europe.fr/Software_Matters
typedef int Time;
typedef int Distance;
typedef int Speed;

const Speed SAFETY_SPEED = 120;

void increase_speed (Speed s);

void check_speed (Time t, Distance d) {
Speed s = d/t;
if (s < SAFETY_SPEED)
increase_speed (t);
}
void perform_safety_checks () {
Time t = get_time ();
Distance d = get_distance ();

check_speed (d, t);
}

• Compila, pero ¿tiene problemas?


12048 - J. Neira – Universidad de Zaragoza 29
5. C .vs. ADA
http://libre.act-europe.fr/Software_Matters
typedef int Time;
typedef int Distance;
typedef int Speed;

const Speed SAFETY_SPEED = 120;

void increase_speed (Speed s);

void check_speed (Time t, Distance d) {
Speed s = d/t;
if (s < SAFETY_SPEED)
increase_speed (t);
}
void perform_safety_checks () {
Time t = get_time ();
Distance d = get_distance ();

check_speed (d, t);
}

• Compila, pero ¿tiene problemas?


12048 - J. Neira – Universidad de Zaragoza 30
5. C .vs. ADA
http://libre.act-europe.fr/Software_Matters
SAFETY_SPEED : constant Integer := 120;

procedure Increase_Speed (S : Integer);

procedure Check_Speed (T : Integer; D : Integer) is
S : Integer := D / T;
begin
if S < SAFETY_SPEED then
Increase_Speed (T);
end if;
end Check_Speed;

procedure Perform_Safety_Checks is
T : Integer := Get_Time;
D : Integer := Get_Distance;
begin

Check_Speed (D, T);
end Perform_Safety_Checks;

• NO compila
12048 - J. Neira – Universidad de Zaragoza 31

You might also like