Sie sind auf Seite 1von 32

Captulo 7

Expresiones y Sentencias de Asignacin


Perfil del Captulo
7.1 Introduccin
7.2 Expresiones Aritmticas
7.3 Sobrecarga de Operadores
7.4 Conversin de Tipos
7.5 Expresiones Booleanas y Relacionales
7.6 Evaluacin de Corto-Circuito
7.7 Sentencias de Asignacin
7.8 Sentencia Mezclada de Asignacin
Como el ttulo lo indica, el enfoque de este captulo son las expresiones y las
sentencias de asignacin. Las reglas de semntica que determinan el orden de
evaluacin de los operadores en expresiones son discutidas primero. Esto se
sigue por los problemas potenciales de implementacin-definida por el orden
de evaluacin de operandos cuando las expresiones pueden tener los efectos
colaterales. La sobrecarga de operadores, ambos predefinidos y definidos por
el usuario, se discute entonces, junto con sus efectos en las expresiones de los
programas. Luego, se discuten las expresiones del modo-mezclado y se
evalan. Esto lleva a la definicin y evaluacin de ampliacin y reduccin de
las conversiones del tipo, implcito y explcito. Las expresiones Boolean y
Relacional son entonces discutidas, incluyendo la idea de evaluacin del
cortocircuito.
Finalmente, la sentencia de asignacin, desde su forma ms simple hasta todas
sus variaciones, se cubre, incluso las asignaciones como las expresiones y
asignaciones del modo-mezclado.
El material en este captulo se restringe a lo convencional ni lenguajes de
programacin funcional y ni lgica, los cuales utilizan notacin infija para las
expresiones lgicas y aritmticas. Los problemas de especificacin de
laexpresin y evaluacin en lenguajes funcional y lgico se discuten en los
Captulos 15 y 16, respectivamente.
Cadenas de caracteres estructuran el modelo de las expresiones discutidas
como una parte del material de cadenas de caracteres en el Captulo 6, por lo
que ellos no se mencionan en este captulo.
7.1 Introduccin
Las expresiones son los medios fundamentales de especificar los cmputos en
un lenguaje de la programacin. Es crucial para un programador entender la
sintaxis y semntica de las expresiones. Se describieron mtodos de describir
la sintaxis de las expresiones en el Captulo 3. En este captulo, nos enfocamos
en la semntica de las expresiones-esto es, que significan ellos-lo cual es
determinado por cmo ellos son evaluados.
Para entender la evaluacin de la expresin, es necesario estar familiarizado
con el orden de evaluacin del operador y del operando. El orden de evaluacin
del operador de expresiones es manejado por la asociatividad y las reglas de

precedencia del lenguaje. Aunque el valor de una expresin a veces depende


de l, el orden de evaluacin del operando en las expresiones es a menudo no
expuesto por los diseadores del lenguaje, una situacin que permite a los
programas producir los resultados diferentes en implementaciones diferentes.
Otros problemas en la semntica de las expresiones son las desigualdades del
tipo, coerciones, y evaluacin del cortocircuito.
La esencia de los lenguajes de la programacin imperativos es el papel
dominante de sentencias de asignacin. El propsito de una sentencia de
asignacin es cambiar el valor de unavariable. As una parte ntegra de todos
los lenguajes imperativos es el concepto de variables cuyos valores cambian
durante la ejecucin del programa. (Los lenguajes imperativos a veces incluyen
variables de una clase diferente, como los parmetros de funciones en los
lenguajes funcionales.)
Una sentencia de asignacin puede causar un valor simplemente para ser
copiado de una celda de memoria a otra. Pero en muchos casos, las sentencias
de asignacin incluyen las expresiones con operadores, las cuales causan
valores para ser copiados al procesador y para ser operados antes, y los
resultados para ser copiados como apoyo a la memoria.
Las sentencias de asignacin simples especifican una expresin a ser evaluada
y una localizacin designada en la cual colocar el resultado de la evaluacin de
expresin. Como veremos en este captulo, hay varias variaciones en este
forma bsica.
7.2 Expresiones Aritmticas
La evaluacin automtica de expresiones aritmticas similar a aquellas
encontrada en matemtica fue una de las metas primarias en la era de los
primeros lenguajes de la programacin de alto nivel. La mayora de las
caractersticas de las expresiones aritmticas en los lenguajes de
programacin fueron heredadas de convenciones que haban evolucionado en
la matemtica. En lenguajes de programacin, las expresiones aritmticas
consisten en operadores, operandos, parntesis, y llamadas a funcin. Los
operadores pueden ser unarios, significando que ellos tienen un solo operando,
o binario, significando que ellos tienen dos operandos. C, C++, y Java incluyen
a un operador ternario que tiene tresoperandos como lo discutidos en la
Seccin 7.2.1.4.
En ms lenguajes de programacin imperativos, los operadores binarios son
infijos, lo cual significa que ellos aparecen entre sus operandos. Una excepcin
es Perl, el cual tiene algunos operadores que son prefijos, lo cual significa que
ellos preceden a sus operandos.
El propsito de una expresin aritmtica es especificar un cmputo aritmtico.
Una implementacin de tal cmputo debe causar dos acciones: sacando los
operando, usualmente de la memoria, y ejecutando las operaciones aritmticas
en esos operandos. En las secciones siguientes, nosotros investigamos los
detalles del diseo comn de expresiones aritmticas en los lenguajes
imperativos.

Siguiendo estn los diseos primarios de los problemas para las expresiones
aritmticas, las cuales todas se discute en esta seccin:
Qu son las reglas de precedencia de operador?
Qu son las reglas de asociatividad de operador?
Qu es el orden de evaluacin del operando?
Hay restricciones en el efecto colateral de la evaluacin de operandos?
El lenguaje permite que el usuario defina una sobrecarga del operador?
Qu modo mezclado es permitido en expresiones?
7.2.1 Orden de Evaluacin del Operador
Nosotros investigamos las reglas del lenguaje que especifican el orden de
evaluacin de los operadores primero.
7.2.1.2 Precedencia
El valor de una expresin depende, por lo menos en parte, del orden de
evaluacin de los operadores en la expresin. Considere la expresin siguiente:
a+b*c
Suponga las variables a, b, y c que tienen los valores 3, 4, y 5,respectivamente.
Evaluado de izquierda a derecha (la suma primero y luego la multiplicacin), el
resultado es 35. Evaluado de derecha a izquierda, el resultado es 23..
En lugar de evaluar el orden simplemente de izquierda a derecha o de derecha
a izquierda, los matemticos han desarrollado el concepto de colocar
operadores en una jerarqua de evaluacin de prioridades y basando el orden
de evaluacin de expresiones en parte en esta jerarqua. Por ejemplo, en
matemtica, se considera que la multiplicacin es de prioridad ms alta que la
suma. Si nosotros seguimos esa convencin en nuestra expresin del ejemplo,
la multiplicacin se evaluara primero.
La regla de precedencia del operador para la evaluacin de la expresin define
el orden en que se evalan los operadores de niveles de precedencia
diferentes. La reglas de precedencia del operador para las expresiones estn
basadas en la jerarqua de prioridades del operador, como son visto por el
diseador del lenguaje. La regla de precedencia del operador de los lenguajes
imperativos comunes son casi todos los mismos, porque ellos estn todos
basados en aquellos de matemtica. En estos lenguajes, la exponenciacin
tiene la precedencia ms alta (cuando es proporcionado por el lenguaje),
siguiendo por la multiplicacin y divisin en el mismo nivel, seguido por la
suma binaria y substraccin en el mismo nivel.
Muchos lenguajes tambin incluyen versiones unarias de suma y substraccin.
La suma unaria es llamada el operador de identidad porque usualmente no
tiene operacin asociada y as no tiene el efecto en su operando. Ellis
yStroustrup, hablando sobre C++, llama e esto un accidente histrico y
correctamente lo etiqueta intil (Ellis y Stroustrup, 1990, pg. 56). En Java, el
unario actualmente tiene un efecto cuando el operando es char, sort, o byteesto causa una conversin implcita de ese operando al tipo del int. El menos
del Unario, claro, siempre cambia el signo de su operando.
En todos los lenguajes imperativos comunes, los operadores menos del unario

pueden aparecer al principio o en cualquier parte en una expresin dentro de la


expresin, con tal de que sea parentizado para impedirle ser adyacente a otro
operador. Por ejemplo,
A + (- B) * C
es legal, pero
A+-B*C
usualmente no es.
Cuando veamos en la seccin 7.2.1.2, la precedencia de los operadores del
unarios es raramente relevante.
La precedencia de los operadores aritmticos de algunos lenguajes de
programacin comunes son como sigue:
FORTRAN Pascal C Ada
Alta ** *, /, div, mod postfija ++, -- **, abs
*, / todos +, - prefija ++, -- *, /, mod
todos +, - unario +, - unario +, *, /, % binario +, Baja binario +, El operador ** es exponenciacin. La / y div operadores de Pascal son
descriptos en la seccin 7.3. El operador % de C esexactamente lo mismo que
el operador mod de Pascal y Ada: Este toma dos operandos enteros y produce
el resto del primero despus de dividirlo por el segundo. Los operadores ++ y - de C son descriptos en la seccin 7.7.5. La regla de precedencia de C++ y
estas de C son las mismas, excepto que en C++, todos los operadores ++ y - tienen igual precedencia. Las reglas de precedencia de Java son estas de C++.
El operador abs de Ada es un operador unario que produce el valor absoluto de
estos operandos.
APL es extrao entre los lenguajes porque este tiene un nico nivel de
precedencia, como lo ilustrado en la prxima seccin.
La precedencia cuenta solo para algunas de las reglas, para el orden de
evaluacin del operador; las reglas de asociatividad tambin las afecta.
7.2.1.2 Asociatividad
Considerar la siguiente expresin:
a-b+c-d
Si los operadores de la suma y de la substraccin tienen el mismo nivel de
precedencia, las reglas de precedencia dicen nada sobre el orden de
evaluacin de los operadores en esta expresin.
Cuando una expresin contiene dos ocurrencias adyacentes de operadores con
el mismo nivel de precedencia, la pregunta por la cual el operador es evaluado
primero se contesta por las reglas de asociatividad del lenguaje. Un operador
puede tener ambas asociatividades izquierda o derecha, significando que la
ocurrencia mas a la izquierda es evaluada primero o la ocurrencia ms a la
derecha es evaluada primero, respectivamente.
Asociatividad en lenguajes imperativos comunes es de izquierda a derecha,
excepto que el operador de exponenciacin (cuando es provisto)asocia de

derecha a izquierda. En Fortran la expresin


AB+C
el operador izquierdo es evaluado primero. Pero la exponenciacin en Fortran
es asociado a la derecha, como en la expresin
A ** B ** C
el operador derecho es evaluado primero.
En Ada, la exponenciacin no es asociativa, lo cual significa que la expresin
A ** B ** C
es ilegal en Ada. Como una expresin puede ser parentizada representa desear
orden, como en ambos
(A ** B) ** C
o
A ** (B ** C)
Ahora podemos explicar el porqu la precedencia de operadores unarios es
ms frecuentemente no importante. Las operaciones menos unario y binario de
Fortran tienen la misma precedencia, pero en Ada (y otros lenguajes comunes
ms) menos unarios tienen precedencia sobre menos binarios. Sin embargo,
considerar la expresin
-A-B
porque Fortran usa asociatividad izquierda para ambos menos unario y menos
binario, y porque Ada obtiene precedencia para menos unario sobre menos
binario, esta expresin es equivalente a
(- A) - B
en ambos lenguajes. Luego considerar la siguiente expresin:
-A/B
-A*B
- A ** B
en el primero de los dos casos, la precedencia relativa del operador menos
unario y el operador binario es irrelevante, el orden de evaluacin de los dos
operadores no tiene efecto en el valor de la expresin. En el ltimo caso, sin
embargo, esto importa. De los lenguajes de programacin comunes, solo
Fortran y Ada tienen operador de exponenciacin. En ambos casos, la
exponenciacin tiene ms alta precedencia que los menos unarios, como en
- A ** B
es equivalente a
-(A ** B)
Cuando los operadores unitarios aparecen en otras posiciones que a la
izquierda final de la expresin, ellos deben ser parentizadas en ambos
lenguajes, como en estas situaciones estos operadores son forzados a tener la
ms alta precedencia (los parntesis son discutidos en la seccin 7.2.1.3).
Las reglas de asociatividad para algunos de los ms comunes lenguajes
imperativos son obtenidas abajo:
Lenguaje Reglas de Asociatividad
Fortran Izquierda: *, /, +, -

Derecha: **
Pascal Izquierda: todos
C Izquierda: postfija ++, postfija - -, *, /, %, binario +, binario
Derecha: prefija ++, prefija - -, unario +, unario
C++ Izquierda: *, /, %, binario +, binario
Derecha: ++, - -, unario -, unario +
Ada Izquierda: todos excepto **
No asociativo: **
Como lo declarado en la seccin 7.2.1.1, en APL, todos los operadores tienen el
mismo nivel de precedencia. As el orden de evaluacin de operadores en las
expresiones de APL es completamente determinado por la regla de
asociatividad, la cual es de derecha a izquierda para todos los operadores. Por
ejemplo, en la expresin
AxB+C
el operador de suma se evala primero, siguiendo por el operador de la
multiplicacin (x es en APL el operador de multiplicacin). Si A era 3, B era 4, y
C era 5, el valor de esta expresin de APL sera 27.
Muchos compiladoreshacen uso del hecho que algunos operadores aritmticos
son matemticamente asociativos, significando que las reglas de asociatividad
no tienen el impacto en el valor de una expresin que contiene slo esos
operadores. Por ejemplo, la suma es matemticamente asociativa, como en la
matemtica el valor de la expresin
A+B+C
no dependa del orden de evaluacin del operador. Si las operaciones de puntoflotante para operaciones matemticamente asociativas tambin fueran
asociativas, el compilador podra usar este hecho para realizar algunas simples
optimizaciones. Especficamente, si el compilador es permitido para reordenar
la evaluacin de operadores, puede poder producir el cdigo ligeramente ms
rpido para la evaluacin de la expresin. Los compiladores actualmente hacen
estos tipos de optimizaciones.
Desdichadamente, los dos, las representaciones del punto-flotante y las
operaciones aritmticas de punto-flotante son slo aproximaciones de
matemtica (debido a las limitaciones del tamao). El hecho que un operador
matemtico es asociativo necesariamente no implica que la correspondiente
operacin de punto-flotante es asociativa. De hecho, slo si todos los
operadores y resultados intermedios pueden representarse exactamente en
notacin de punto-flotante ser el proceso precisamente asociativo. Por
ejemplo, hay situaciones patolgicas en las cuales la suma de entero en una
computadora no es asociativa. Por ejemplo, suponga que un programa debe
evaluar la expresin

A+B+C+D
y que A y C son muy largos nmeros positivos, y B y D son nmeros negativos
con muy largos valoresabsolutos. En esta situacin, agregando B a A no causa
un sobre fluido, pero agregando C a A, si. Igualmente, agregando C a B no
causa el sobre fluido, pero agregando D a B, si. Debido a las limitaciones de
aritmtica de la computadora, la suma es catastrficamente el no asociativo en
este caso. Por consiguiente, si el compilador reordena estas operaciones de
suma, afecta al valor de la expresin. Esto es, claro, un problema que puede
ser evitado por el programador, asumiendo que los valores aproximados de las
variables son conocidos. El programador puede simplificar parentizando la
expresin (vea seccin 7.2.1.3) para asegurar que slo el orden seguro de la
evaluacin es posible. Sin embargo, esta situacin puede levantarse de
maneras ms sutiles, en las que el programador probablemente notar menos
el orden de dependencia.
7.2.1.3 Parntesis
Los Programadores pueden alterar las reglas de precedencia y la asociatividad
colocando parntesis en las expresiones. Una parte de la parentizacin de una
expresin tiene la precedencia sobre sus partes no parentizadas adyacentes.
Por ejemplo, aunque la multiplicacin tiene la precedencia sobre la suma, en la
expresin
(A + B) * C
la suma se evaluar primero. Matemticamente, esto es perfectamente
natural. En esta expresin, el primer operando del operador de la
multiplicacin no est disponible hasta que la suma en la parentizacin de la
subexpresin es evaluada.
Lenguajes que permiten los parntesis en las expresiones aritmticas podran
distribuirse con todas las reglas de precedencia y simples asociatividad; todos
los operadores deizquierda a derecha o de derecha a izquierda. El programador
especificara el orden deseado de evaluacin con los parntesis. Esto sera
simple porque ni el autor ni los lectores de programas necesitaran recordar
cualquier regla de precedencia o asociatividad. La desventaja de este esquema
es que hace las expresiones escritas ms tediosas, y tambin compromete
seriamente la legibilidad del cdigo. Todava esta era la opcin hecha por Ken
Iverson, el diseador de APL.
7.2.1.4 Expresiones Condicionales
Ahora miremos al operador ternario ?: el cual es parte de C, C++, y Java. Este
operador es utilizado para formar las expresiones condicionales.
A veces se utilizan las sentencias if-then-else para realizar una asignacin de la
expresin condicional. Por ejemplo, considere
if (count = =0)
average = 0
else
average = sum / count;

En C, C++, y Java, esto puede especificarse ms convenientemente en una


sentencia de asignacin utilizando una expresin condicional que tiene la
forma
expresin_1 ? expresin2 : expresin_3
donde la expresin_1 es interpretada como una expresin Bolean. Si la
expresin_1 evala para verdadero, el valor de toda expresin es la del valor
de la expresin_2; si no, este es el valor de la expresin_3. Por ejemplo, el
efecto del if-then-else de abajo puede ser realizado con la siguiente sentencia
de asignacin, utilizando una expresin condicional:
average = (count = = 0) ? 0 : sum / count;
En efecto, el signo de interrogacin denota el principio de la clusula then, y
los dos puntosmarcan el principio de la clusula else. Ambas clusulas son
obligatorias. Noto que? es utilizada en expresiones condicionales como un
operador ternario.
Pueden utilizarse las expresiones condicionales en cualquier parte en
programas C, C++, o Java dnde cualquier otra expresin puede utilizarse.
7.2.2 Orden de Evaluacin de los Operandos
Comnmente menos discutido es el diseo de las caractersticas de las
expresiones en el orden de evaluacin de los operandos. Las variables en las
expresiones son evaluadas sacando sus valores de la memoria. A veces se
evalan las constantes de la misma manera. En otros casos, una constante
puede ser parte de la instruccin del lenguaje de mquina y no requiere traerlo
de la memoria. Si un operando es una expresin parentizada, entonces todos
los operandos contenidos deben evaluarse antes de que su valor pueda
utilizarse como un operando.
Si ninguno de los operandos de un operador tiene los efectos colaterales,
entonces el orden de evaluacin del operando es irrelevante. Por consiguiente,
el nico caso interesante se sugiere cuando la evaluacin de un operando tiene
los efectos colaterales.
7.2.2.1 Efectos Colaterales
Un efecto colateral de una funcin, es llamada un efecto colateral funcional,
ocurre cuando la funcin cambia cualquiera de los dos, o sus parmetros o una
variable global. (Una variable global se declara fuera de la funcin pero es
accesible en la funcin.)
Considere la expresin
a + fun(a)
Si fun no tiene el efecto colateral de cambiar a, entonces el orden de
evaluacin de los dos operandos, a y fun (a), no tiene elefecto en el valor de la
expresin. Sin embargo, si fun cambia a, hay un efecto. Considere la situacin
siguiente: fun devuelve el valor de su argumento dividido por 2 y cambia su
parmetro para tener el valor 20. Suponga que nosotros tenemos lo siguiente:
a = 10;
b = a + fun(a);
Entonces, si el valor de a se saca primero (en el proceso de evaluacin de

expresin), su valor es 10 y el valor de la expresin es 15. Pero si el segundo


operando se evala primero, entonces el valor del primer operando es 20 y el
valor de la expresin es 25.
El siguiente programa en C ilustra el mismo problema cuando una funcin
cambia una variable global que aparece en una expresin:
int a = 5;
int fun1() {
a = 17;
return 3;
} /* de fun1 */
void fun2() {
a = a + fun1();
} /* de fun2 */
void main() {
fun2();
} /* de main */
El valor computado para a en fun2 depende del orden de evaluacin de los
operandos en la expresin a + fun1 (). El valor de a ser u 8 o 20.
Hay dos soluciones al problema de orden de evaluacin del operando. Primero,
el diseador del lenguaje podra desaprobar la evaluacin de la funcin
desafectando los valores de expresiones por una simple desaprobacin
funcional del efecto colateral. El segundo mtodo de evitar el problema es
declarar en la definicin del lenguaje que los operandos en las expresiones
sern evaluadas en un orden particular y se exigir la garanta del
implementador que la ordene.
Desaprobando los efectos colaterales funcionales es difcil, y esto elimina un
poco la flexibilidad por el programador.Considere el caso de C y C++ que
tienen slo funciones. Eliminar los efectos colaterales de parmetros
bidireccionales y todava proporcionar subprogramas que devuelven ms de un
valor, un nuevo tipo del subprograma que es similar a los procedimientos de
los otros lenguajes imperativos se exigira. El acceso a variables globales en las
funciones tambin tendra que ser desaprobado. Sin embargo, cuando la
eficacia es importante, usando el acceso a las variables globales, evitar pasar
el parmetro es un mtodo importante aumentando la rapidez en la ejecucin.
En los compiladores, por ejemplo, el acceso global a los datos como la tabla de
smbolos es comn.
El problema con tener un orden de la evaluacin estricto es que algunas
tcnicas de optimizacin de cdigo utilizadas por los compiladores involucran
la reordenacin de evaluaciones del operando. Un desaprobado orden
garantiza esos mtodos de la optimizacin cuando las llamadas a funciones
estn involucradas. No hay ninguna solucin perfecta por consiguiente, como
es confirmado por los diseos del lenguaje actual.
Los diseadores de FORTRAN 77 previeron una tercera solucin. La definicin
de FORTRAN 77 declara que expresiones que tienen llamadas a funcin slo

son legales si las funciones no cambian los valores de otros operandos en la


expresin. Desdichadamente, no es fcil para el compilador determinar el
efecto exacto que una funcin puede tener en las variables fuera de la funcin,
especialmente en la presencia de variables globales proporcionada por
COMMON y los alias proporcionado por el EQUIVALENCE. ste es un caso dnde
ladefinicin especfica del lenguaje bajo la cual condiciona una estructura que
es legal pero deja al programador asegurar que tales estructuras son
especficamente legales en el programa.
Pascal y Ada permiten evaluar los operandos de operadores binarios en
cualquier orden escogido por el implementador. Adems, las funciones en estos
lenguajes pueden tener los efectos colaterales, para que el problema discutido
abajo pueda ocurrir. Se discuten los efectos colaterales funcionales en el
Captulo 9.
La definicin del lenguaje Java garantiza que los operandos aparecen para ser
evaluados en el orden de izquierda-a-derecha, eliminando el problema
discutido en esta seccin.
7.3 Sobrecarga del Operador
Los operadores aritmticos se usan a menudo para ms de un propsito. Por
ejemplo, + frecuentemente se usa para la suma de cualquier operando del tipo
numrico. Algunos lenguajes, Java por ejemplo, tambin lo usa para la
concatenacin de cadenas. Este mltiple uso de un operador se llama
sobrecarga de operador y generalmente se piensa que es aceptable, con tal de
que la legibilidad y/o fiabilidad no sufran. Algunos creen que hay demasiada
sobrecarga de operador APL y SNOBOL dnde la mayora de los operadores se
usan para operaciones unarias y binarias.
Como un ejemplo de los posibles peligros de sobrecarga, considere el uso del
ampersand (&) en C. Como un operador binario, especifica un papel prudente
lgico de la operacin AND. Como operador de unario, sin embargo, su
significado es totalmente diferente. Como operador de unario con una variable
como su operando, el valor de la expresin esla direccin de esa variable. En
este caso, el ampersand se llama la direccin del operador. Por ejemplo, la
ejecucin de
x = & y;
causa la direccin de y para ser puesto en x. Hay dos problemas con este
mltiple uso del ampersand. Primero, usando el mismo smbolo para dos
completamente no relacionadas operaciones es perjudicial a la legibilidad.
Segundo, el error del tecleo simple de omitir el primer operando para un papel
prudente de operacin AND puede ir no detectado por el compilador, porque se
interpreta como un direccin-de operador. Tal como un error puede ser difcil
diagnosticar.
Virtualmente todos los lenguajes de programacin tienen un problema menos
serio pero similar que es a menudo debido a la sobrecarga del operador menos.
El problema es slo que el compilador no puede determinar si el operador
quiere decir ser binario o unario. As una vez ms, fracasa la inclusin del

primer operando cuando el operador significa ser binario no pudiendo ser


detectado como un error por el compilador. Sin embargo, los significados de las
dos operaciones, unaria y binaria, se relacionan por lo menos estrechamente,
para que la legibilidad no se afecte adversamente.
Los distintos smbolos del operador no slo aumentan la legibilidad, sino que
ellos a veces son tambin convenientes al uso comn de las operaciones. El
operador de la divisin es un ejemplo. Considere el problema de encontrar el
promedio del punto flotante de una lista de enteros. Normalmente la suma de
esos enteros se computa como un entero. Suponga que esto se ha hecho en la
variable sum, y el nmero de valoresest en count. Ahora, si el promedio del
punto flotante es computado y se coloca en la variable avg de punto flotante,
este cmputo podra especificarse en C++ como
avg = sum / count;
Pero esta asignacin produce un resultado incorrecto en la mayora de los
casos. Porque ambos operandos del operador de la divisin son el tipo del
entero, una operacin de divisin de entero toma lugar en el resultado que es
truncado a un entero. Entonces, a pesar de que el destino (avg) es el tipo del
punto flotante, su valor de esta asignacin no puede tener una parte
fraccionaria. El resultado de la divisin del entero se convierte a punto flotante
para la asignacin despus del truncamiento de la divisin del entero.
Cuando un smbolo distinto del operador para la divisin del punto flotante est
disponible, la situacin se simplifica. Por ejemplo, en Pascal dnde / significa la
divisin del punto flotante, la siguiente asignacin pueden usarse
avg := sum / count
donde avg es del tipo del punto flotante, y sum y count son del tipo del entero.
Se convertirn ambos operandos implcitamente para el punto flotante, y una
operacin de divisin del punto flotante es utilizada. Este tipo de operacin de
conversin implcita se discute en la seccin siguiente. La divisin del entero en
Pascal se especifica por el operador div que toma los operandos del entero y
produce un resultado del entero. Cuando ningn operador distinto para la
divisin del punto flotante se proporciona, deben usarse las conversiones
explcitas. Se discuten tales conversiones en la seccin 7.4.2.
Algunoslenguajes que soportan los tipos de datos abstractos (vea Captulo 11);
por ejemplo, Ada, C++, y FORTRAN 90 permiten al programador la extensa
sobrecarga de los smbolos del operador. Por ejemplo, suponga que un usuario
quiere definir el operador * entre un escalar entero y un array de entero para
significar que cada elemento del array ser multiplicado por el escalar. Esto
podra hacerse escribiendo un subprograma funcin nombrado * que realiza
esta nueva operacin. El compilador escoger el significado correcto cuando
una sobrecarga de operador se especifica, basado en los tipos de los
operandos, como con la sobrecarga de operadores definidos en los lenguajes.
Por ejemplo, si esta nueva definicin para * se define en un programa de Ada,
un compilador de Ada usar la nueva definicin para * siempre que el operador
* aparece con un entero simple como el operando izquierdo y un array de

entero como el operando derecho.


Cuando sensiblemente usa, los operadores sobrecargados definidos por el
usuario puede ayudar a la legibilidad. Por ejemplo, si + y * se sobrecargan por
una matriz de tipos de datos abstractos y A, B, C, y D son las variables de ese
tipo, entonces,
A*B+C*D
Puede ser utilizado a cambio de
MatrixAdd(MatrixMult(A, B), MatrixMult(C, D))
Por otro lado, la sobrecarga definida por el usuario puede ser daina para la
legibilidad. En primer lugar, nada previene a un usuario definir + para significar
multiplicacin. Adems, viendo un operador de * en un programa, el lector
debe hallar ambos tipos de operandos y la definicin del operador
paradeterminar este significado. Cualquiera o todas estas definiciones podran
estar en otros archivos.
C++ tiene algunos operandos que no pueden ser sobrecargados. Entre estas
estn el class u operador miembro de estructura (.) y el operador de resolucin
del mbito (::). Interesantemente, la sobrecarga del operador fue una de las
caractersticas de C++ que fue copiada por Java
7.4 Conversiones de Tipos
Las conversiones de tipos son o reducidas o ampliadas. Una conversin
reducida convierte un valor a un tipo que no puede guardar incluso las
aproximaciones de todos los valores del tipo original, por ejemplo, convirtiendo
un double a un float en Java (el rango de double es ms grande que el del
float). Una conversin ampliada convierte un valor a un tipo que puede incluir
las aproximaciones por lo menos de todos los valores del tipo original, por
ejemplo, convirtiendo un int a un float en Java. Las conversiones ampliadas
casi siempre estn seguras, considerando que las conversiones reducidas no lo
son.
Como un ejemplo de un problema potencial con una conversin ampliada,
considere lo siguiente. En muchas implementaciones del lenguaje, aunque las
conversiones del entero a float son conversiones ampliadas, alguna exactitud
puede perderse. Por ejemplo, en algunas implementaciones, se guardan los
enteros en 32 bits, que permite por lo menos nueve dgitos decimales de
precisin. Pero en muchos casos, se guardan tambin los valores del punto
flotante en 32 bits, con slo aproximadamente siete dgitos decimales de
precisin. As que, el entero a punto flotante ampliado puede resultar en la
prdida dedos dgitos de precisin.
Las conversiones de tipos pueden ser explcitas o implcitas. Las siguientes dos
subsecciones discuten estos dos tipos de conversiones del tipo.
7.4.1 Coerciones en Expresiones
Una de las decisiones del diseo concerniente a las expresiones aritmticas es
si un operador puede tener operandos de tipos diferentes. Lenguajes que
permiten tales expresiones se llaman expresiones del modo-mixto, debe definir
las convenciones para las conversiones de tipo de operando implcitas,

llamadas coerciones, porque las computadoras usualmente no tienen


operaciones binarias que tomen operandos de diferentes tipos. Recordemos
que en el Captulo 5 definimos coercin para ser una conversin del tipo
implcito que se inicializa por el compilador. Nosotros nos referimos al tipo de
conversin explcita requerida por el programador como las conversiones
explcitas, o lanzamientos, no coerciones.
Aunque algunos smbolos del operador pueden ser sobrecargados, asumimos
que un sistema de la computadora, o en el hardware o en algn nivel de
simulacin del software, se opera para cada tipo del operando y operador
definido en el lenguaje. Para la sobrecarga de operadores en un lenguaje que
usa el tipo esttico obligado, el compilador escoge el tipo correcto de operacin
en base a los tipos de los operandos. Cuando los dos operandos de un
operador no son del mismo tipo y eso es legal en el lenguaje, el compilador
debe escoger uno de ellos para ser coercionado y proporcionar el cdigo para
esa coercin. En la siguiente discusin, examinamos las opciones de diseo de
coercin devarios lenguajes comunes.
Los diseadores del lenguaje no estn de acuerdo en el problema de las
coacciones en las expresiones aritmticas. Aquellos contra un rango ancho de
coacciones se preocupan por los problemas de fiabilidad que pueden ser el
resultado de las tales coacciones, porque ellos eliminan los beneficios de
comprobacin del tipo. Aquellos que incluiran ms bien todas estas coacciones
se preocupan ms por la flexibilidad que del resultado de las restricciones. El
problema es si programadores deben tener relacin con esta categora de
errores o si el compilador debe descubrirlos.
Como una ilustracin simple del problema, considere el mtodo de Java del
siguiente esqueleto:
void myMethod() {
int a, b, c;
float d;

a = b * d;

}
Asuma que el segundo operando del operador de la multiplicacin era
supuestamente c, pero debido a un error del tecleo se tecle como d. Porque
las expresiones del modo-mixto son legales en Java, el compilador no
descubrira esto como un error. Insertara el cdigo simplemente para
coaccionar el valor del otro operando, b, a float. Si las expresiones del modomixto no fueran legales en Java, este error del tecleo se habra descubierto por
el compilador como un error de tipo.
Como un ejemplo ms extremo de los peligros y costos de demasiada coaccin,
considere los esfuerzos de PL/I para lograr la flexibilidad en las expresiones. En
PL/I, unavariable de cadena de caracteres puede combinarse con un entero en
una expresin. En tiempo de ejecucin, la cadena se examina para un valor

numrico. Si el valor pasa para contener un punto decimal, se asume que el


valor es de tipo del punto flotante, el otro operando se coacciona para punto
flotante, y el resultado de la operacin es punto flotante. Esta poltica de
coaccin es muy cara porque deben hacerse el chequeo del tipo y la
conversin en el tiempo de ejecucin. Tambin elimina la posibilidad de
deteccin de errores en expresiones por el programador, porque un operador
binario puede combinar un operando de cualquier tipo con un operando de
virtualmente cualquier otro tipo.
Porque el descubrimiento del error est reducido cuando se permiten las
expresiones del modo-mixto, Ada permite muy pocos tipos de operandos en
expresiones mixtas. No permite mezcla de operando entero y operando del
punto flotante en una expresin, con una excepcin: El operador de
exponenciacin, * *, puede tomar un punto flotante o un entero para el primer
operando y un tipo entero para el segundo operando. Ada permite algunos
otros tipos de operando para mezclar los tipos, normalmente relacionado a los
tipos del subrango.
En la mayora de los otros lenguajes comunes, no hay ninguna restriccin del
modo-mixto de las expresiones aritmticas.
C++ y Java tienen tipos del entero que son ms pequeos que el tipo del int.
En C++, stos son char y short int; en Java, ellos son byte, short, y char. Los
operando de todos estos tipos se coaccionan al int siempre que virtualmente
cualquier operador se apliquea ellos. As mientras pueden guardarse los datos
en las variables de estos tipos, no pueden ser manipulados antes de la
conversin a un tipo ms grande.
Por ejemplo, considere el siguiente cdigo en Java:
byte a, b, c;

a= b + c;
Los valores de b y c son coaccionados a int y una suma int es representada.
Luego la suma es convertida a byte y colocada en a.
7.4.2 Conversin del Tipo Explcito
La mayora de los lenguajes proveen un poco de capacidad haciendo las
conversiones explcitas, ambas reduciendo y ampliando. En algunos casos, los
mensajes de advertencia son producidos cuando el resultado de una
conversin reducida explcita cambia el significado para el valor del objeto al
inicio de la conversin
Ada proporciona operaciones de conversin explcitas que tienen la sintaxis de
llamadas de la funcin. Por ejemplo, nosotros podemos tener
AVG := FLOAT(SUM) / FLOAT(COUNT)
donde AVG es del tipo punto flotante, y SUM y COUNT pueden ser cualquier
tipo numrico.
En el lenguaje basado en C, la conversin del tipo explcito es llamada cast
(lanzar). Las sintaxis de un cast no es de una llamada a funcin; ms bien, el
tipo deseado es colocado en parntesis slo antes de ser convertida la

expresin. Como se representa en


(int) angle
Una de las razones de conversin de los parntesis en C es que C tiene varios
tipos llamados doble-palabra, como el long int.
7.4.3 Errores en Expresiones
Un nmero de errores puede ocurrir en una expresin de evaluacin. Si el
lenguaje requiere chequeo de tipo, entonces el error de tipo operando no
puedeocurrir. Ya discutiremos el error que puede ocurrir debido a las
coacciones de operandos en expresiones. Los otros tipos de errores son
debidos a las Iimitaciones de aritmtica de la computadora y las limitaciones
inherentes de aritmtica. El error ms comn se crea cuando el resultado de
una operacin no puede representarse en la celda de memoria dnde debe
guardarse. Esto se llama sobre fluido o no fluido, dependiendo si el resultado
tambin era demasiado largo o demasiado pequeo. Una limitacin de la
aritmtica es la divisin por cero no permitida. Claro, el hecho que no se
permite matemticamente no impide a un programa intentar hacerlo.
El sobre fluido y el no fluido del punto flotante, y la divisin por el cero son
ejemplos de errores en tiempo de ejecucin, que a veces se llaman
excepciones. Los recursos del lenguaje que permiten a los programas descubrir
y tratar con las excepciones se discuten en el Captulo 14.
7.5 Expresiones Booleans y Relacionales
En la suma de expresiones aritmticas, los lenguajes de programacin tienen
expresiones booleanas y relacionales.
7.5.1 Expresiones Relacionales
Un operador relacional es un operador que compara los valores de sus dos
operandos. Una expresin relacional tiene dos operandos y un operador
relacional. El valor de una expresin relacional es Boolean, excepto cuando
Boolean no es un tipo en el lenguaje. Los operadores relacionales son a
menudo sobrecargados por la variedad de tipos. La operacin que determina la
verdad o falsedad de una expresin relacional depende del tipo del operando.
Puede ser simple, en cuanto a los operando delentero, o complejo, en cuanto a
los operando de cadena de caracteres. Tpicamente, los tipos de los operando
que pueden usarse para los operadores relacionales son tipos numricos,
cadenas, y los tipos ordinales.
La sintaxis de los operadores relacionales disponible en algunos lenguajes
comunes son como sigue:
Operacin Ada Java Fortran 90
Igual = = = .EQ. o ==
No igual /= != .NE. o
Mayor que > > .GT. o >
Menor que < < .LT. o <
Mayor o igual que >= >= .GE. o >=
Menor o igual que B and A < C or K = 0
Es ilegal en Ada. Esta expresin puede ser legalmente escrita como

(A > B and A < C) or K = 0


o
A > B and (A < C or K = 0)
El operador Boolean de Ada and then y or else son discutidos en la prxima
seccin
El C es raro entre los lenguajes imperativos populares porque no tiene ningn
Boolean tipo y as ningn valor de Boolean. En cambio, se usan los valores
numricos para representar los valores de Boolean. En lugar de los operandos
de Boolean, se usan variables numricas y constantes, con cero considerado
falso y todos los valores no ceros considerados verdadero. El resultado de
evaluar tal expresin es un entero, con el valor 0 si es falso y 1 si es
verdadero.
Un resultado raro del diseo de C es la expresin
a>b>c
es legal. El operador relacional ms a la izquierda se evala primero porque los
operadores relacionales de C estn a la izquierda asociados, produciendo 0 o 1.
Entonces este resultado se compara con la variable c. Nunca hay una
comparacin entre b y c.
Cuando los operadores no aritmticos de C, C++, yJava son incluidos, hay ms
de 40 operadores y por lo menos 15 niveles diferentes de precedencia. sta es
evidencia clara de la riqueza de las colecciones de operadores y la complejidad
de las expresiones posibles en estos lenguajes.
Los dictados de legibilidad que un lenguaje debe incluir en un tipo de Boolean,
lo declaramos en el Captulo 6, en lugar de utilizar tipos numricos
simplemente en las expresiones de Boolean, como en C. Algn descubrimiento
del error est perdido en el uso de los tipos numricos de C, porque cualquier
expresin numrica, si intenta o no, es un operando legal a un operador de
Boolean. En otros lenguajes imperativos, cualquier expresin no Boolean usada
como un operando de un operador de Boolean se descubre como un error.
En Pascal, los operadores de Boolean tienen la ms alta precedencia que los
operadores relacionales, para la expresin
a > 5 or a < 0
es ilegal (porque 5 no es un operando Boolean legal). La versin correcta es
(a > 5) or (a < 0)
7.6 Evaluacin del Cortocircuito
Una evaluacin de cortocircuito de una expresin es uno en el cual el resultado
es determinado junto a la evaluacin de todos los operandos y/o operadores.
Por ejemplo, el valor de la expresin aritmtica
(13 * a) * (b / 13 - 1)
es independiente del valor de (b / 13 - 1) si a es 0, porque 0 * x = 0 para
cualquier x. As cuando a es 0 no hay necesidad de evaluar (b / 13 -1) o
representar la segunda multiplicacin. Sin embargo, en expresiones aritmticas
este corto circuito no es fcil de detectar durante la ejecucin, as esto nunca
es tomado.

El valor de laexpresin Bolean


(a >= 0) and (b < 10)
es independiente de la segunda expresin relacional si a < 0, porque (FALSE
and x) es FLASE para todos los valores de x. As cuando a < 0, no hay
necesidad de evaluar b, la constante 10, la segunda expresin relacional, o la
operacin and. Distinto a los casos de expresiones aritmticas, este
cortocircuito puede ser fcilmente descubierto durante la ejecucin y tomada.
Para ilustrar el potencial problema de las expresiones Bolean con una
evaluacin sin cortocircuito, suponga que Java no tiene evaluacin de
cortocircuito. Ahora suponga que escribimos en una tabla parecida al ciclo
usando la sentencia while. Una simple versin del cdigo Java parecido,
asumiendo que list, el cual tiene lista de elementos listlen, que es un array a
ser buscado y la clave es buscada por valores,
index = 1;
while ((index < listlen) && (list [index] key))
index = index + 1
Si la evaluacin no es de corto circuito, ambos la expresin relacional en la
expresin Boolean de la sentencia while es evaluada sin tener en cuenta el
valor del primero. As, si la clave no est en list, el programa terminar con un
error de fuera-de-rango del subndice. La misma iteracin que tiene index ==
listlen referenciar list [listlen], el cual causa el error de posicionamiento
porque la list se declara para tener listlen-1 como un valor del subndice
limitado superior.
Si un lenguaje proporciona evaluacin de cortocircuito de expresiones Boolean
y se usa, ste no es un problema. En el ejemplo precedente, un esquema de
evaluacin de cortocircuito evaluara elprimer operando del operador AND,
pero saltara al segundo operando si el primero operando es falso.
La evaluacin de cortocircuito de expresiones expone el problema de permitir
efectos colaterales en expresiones. Suponga que la evaluacin de cortocircuito
es utilizada en una expresin y parte de la expresin que contiene un efecto
colateral no es evaluado; entonces el efecto colateral slo ocurrir en
evaluaciones completas de toda expresin. Si la correccin del programa
depende del efecto colateral, la evaluacin de cortocircuito puede resultar en
un serio error. Por ejemplo, considere la expresin en C el programa
(a > b) II (b++ / 3)
En esta expresin, b se cambia (en la segunda expresin aritmtica) slo
cuando a
| step until
| while
Un significado diferente entre este y otros ciclos controlados por contador en
estas construcciones es que pueden combinar un contador y una expresin
Boolean para el control de los ciclos. Las tres ms simples formas son
ejemplificadas siguientemente:
for count := 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 do

list [count] := 0
for count := 1 step 1 until 10 do
list [count] := 0
for count := 1, count + 1 while (count 0 goto out
[loop body]
for_var = for_var + step
goto loop
out:
abajo est una descripcin semntica operacional de ejemplos ms complejos
de sentencia for:
for count := 10 step 2 * count until init * init, 3 * count while sum 0 goto loop2
sum = sum + count
count = count + step
goto loop1
loop2:
count = 3 * count
if sum > 1000 goto out
sum =sum + count
goto loop2
out:
8.4.1.4 La sentencia for del Pascal
La sentencia for de Pascal es el modelo de simplicidad. Su forma es
for variable := valor_inicial (to | downto) valor_final do sentencia
La opcin to | downto permite que el valor de la variable crezca o disminuya en
los pasos de a 1. Las opciones del diseo for de Pascal son como sigue: La
variable ciclo debe ser un tipo ordinal, y este tiene el mbito de su declaracin.
En el fin del ciclo normal, la variable ciclo es indefinida. Si el ciclo es terminado
prematuramente, tiene su ltimo valor. La variable ciclo no puede ser
cambiada en el cuerpo del ciclo. Los valores inicial y final, los cuales pueden
ser expresiones de cualquier tipo que son compatibles con la variable del ciclo,
puede ser cambiados en el ciclo, pero porque ellos son evaluados solo una vez,
esto no puede afectar el control del ciclo.
8.4.1.5 La sentencia for de Ada
La sentencia for de Ada es similar a la versin de Pascal. Este es un pre
examinado ciclo con la forma:
for variable in [reserve] rango_discreto loop

end loop;
Un rango discreto es un subrangos de enteros o un tipo enumerado, tal como
1..10.
La nueva caracterstica ms interesante de la sentencia for de Ada el mbito de
la variable ciclo, la cual es el rango del ciclo. La variable es implcitamente
declarada en la sentencia for e implcitamente no declarada despus del fin del
ciclo. Por ejemplo, en:

COUNT : FLOAT := 1.35;


for COUNT in 1..10 loop
SUM := SUM + COUNT;
end loop:
La variable FLOAT COUNT no es afectada por el ciclo for. Al terminarel ciclo, la
variable COUNT es todava de tipo FLOAT con el valor 1.35. Tambin la variable
de tipo FLOAT, COUNT es ocultada del cdigo en el cuerpo del ciclo, siendo
enmascarado por el contador del ciclo COUNT, el cual es implcitamente
declarado para ser el tipo de rango discreto, INTEGER.
La variable del ciclo de Ada no puede ser asignada un valor en el cuerpo del
ciclo. Las variables usadas para especificar el rango discreto puede ser
cambiadas en el ciclo, pero porque el rango es evaluado solo una vez, estos
cambios no afectan el control del ciclo. Esta bifurcacin no es legal dentro del
cuerpo del ciclo for de Ada. Abajo est una descripcin semntica operacional
del ciclo for de Ada:
[define for_var (este es el tipo de rango discreto)]
[rango discreto evaluado]
loop:
if [no hay elementos izquierdo en el rango discreto] goto out
for_var = [prximo elemento del rango discreto]
[loop body]
goto loop
out:
[indefinido for_var]
8.4.1.6 La sentencia for de C, C++, y Java
La forma general de la sentencia for de C es:
for (expresin_1; expresin_2; expresin_3)
loop body
El cuerpo de la sentencia puede ser una sola sentencia, una sentencia
compuesta, o una sentencia nula.
Porque las sentencias en C producen resultados y as pueden ser consideradas
expresiones, las expresiones en una sentencia for son frecuentemente
sentencias. La primera expresin es para inicializacin y es evaluada solo una
vez, cuando la sentencia for inicia su ejecucin. La segunda expresin es el
ciclo de control y es evaluada antes de cada ejecucin del cuerpo del cdigo.
Comoes inusual en C, un valor cero significa falso y todo valor no cero significa
verdadero. Por lo tanto, si el valor de la segunda expresin es cero, el for es
terminado; de otra manera las sentencias del ciclo son ejecutadas. La ltima
expresin en el for es ejecutada antes de cada ejecucin del cuerpo del ciclo.
Esto es frecuentemente usado para incrementar el contador del ciclo. Una
descripcin semntica operacional de la sentencia for de C es mostrada abajo.
Porque las expresiones de C son tambin sentencias, mostraremos evaluacin
de expresin como sentencias.
expresin_1

loop:
if expresin_2 = 0 goto out
[loop body]
expression_3
goto loop`
out:
Un tpico contador del ciclo de C es
for (index = 0; index > indat;
while (indat >= 0) {
sum += indat;
cin >> indat;
}
cin >> valor;
do {
valor /= 10;
dgitos ++;
} while (valor > 0);
Note que todas la variables en estos ejemplos son de tipo entero. cin es el flujo
de entrada estndar (el teclado), y >> es el operador de entrada.
En la versin pre examinada (while) la sentencia es ejecutada tan largo como
la expresin evala verdadero. En C, C++ y Java las sentencias post
examinadas (do), del cuerpo del ciclo es ejecutada hasta la que la expresin
evala falso. La sola diferencia real entre el do y el while es que el do siempre
causa que el cuerpo del ciclo sea ejecutado por lo menos una vez. En ambos
casos, la sentencia puede ser compuesta. Las descripciones semnticas
operacionales de estas dos sentencias son obtenidas abajo:
while do-while
loop: loop:
if expresin = 0goto out [cuerpo del ciclo]
[cuerpo del ciclo] if expresin = 0 goto loop
goto loop
out: ...
Es legal en ambos C y C++ bifurcar dentro de ambos cuerpos de ciclos while y
do.
Las sentencias while y do de Java son similares a las de C y C++, excepto la
expresin de control debe ser del tipo boolean, y porque Java no tiene un goto,
los cuerpo del ciclo no pueden ser introducidos por cualquier parte sino por su
origen.
FORTRAN 90 no tiene ni un pre examinador ni un post examinador de ciclo
lgico. Ada tiene un pre examinador de ciclo lgico pero no una versin de post
examinador de ciclo lgico.
Perl tiene dos pre examinadores de ciclos lgicos, while y until, pero no post
examinador de ciclo. El until es similar a while pero usa el valor inverso de la
expresin de control.

La sentencia post examinadora del ciclo lgico de Pascal, repeat-until, difiere


del do-while de C, C++ y Java en que la expresin de control lgico es
reservada. El cuerpo del ciclo es ejecutado mientras que la expresin evaluada
sea falsa, en lugar de verdadero, como es en el caso de C, C++ y Java.
repeat-until es extrao porque su cuerpo puede ser o una sentencia compuesta
o una secuencia de sentencia. Es solo la estructura de control de Pascal con su
flexibilidad. Este es otro ejemplo de la falta de ortogonalidad en el diseo de
Pascal.
Los ciclos post examinados son infrecuentemente conveniente y tambin
puede ser algunas veces daino en el sentido que los programadores algunas
veces pierden el cuerpo del ciclo que siempre ser ejecutado por lo menos una
vez. El diseosintctico de colocar el control post examinador despus del
cuerpo del ciclo, donde este tiene su efecto semntico, ayuda a evitar tal
problema confeccionando una lgica clara.
8.4.3 Mecanismos de Control de Ciclos Localizados por el Usuario
En algunas situaciones, es conveniente para un programador escoger una
localizacin para otro control del ciclo que est es el tope o en el fondo del
ciclo. Como resultado, algunos lenguajes proporcionan esta capacidad. Un
mecanismo sintctico para el control del ciclo localizado por el usuario puede
ser relativamente simple, para que su diseo no sea difcil. Quizs la pregunta
ms interesante es si un solo ciclo o varios ciclos anidados pueden terminarse.
El problema del diseo para tal mecanismo es lo siguiente:
Debera el mecanismo condicional ser una parte integral de la salida?
Debera el mecanismo ser permitido aparecer en un ciclo controlado o slo en
uno sin cualquier otro control?
Debera slo un cuerpo del ciclo ser terminado, o puede tambin adjuntar los
ciclos terminados?
Varios lenguajes, incluso Ada, tienen sentencias de ciclo que no tienen el
control de la iteracin; ellos son ciclos infinitos a menos que los controles sean
agregados por l programador. El forma del ciclo infinito de Ada es
loop
...
end loop
El exit de Ada puede ser condicional o incondicional, y esto puede aparecer en
cualquier ciclo. Su forma general es
exit [nombre_ciclo] [when condicin]
Con ninguna de las partes opcionales, exit causa le terminacin de solo el ciclo
en el cual aparece. Por ejemplo, en
loop
...
if SUM >= 10000then exit; end if:

end loop;

el exit, cuando se ejecuta, transfiere el control de la primera sentencia despus


del final del ciclo.
Un exit con un when termina la condicin de su ciclo solo si la condicin
especfica es verdadera. Por ejemplo, el ciclo de abajo puede ser escrito como
loop
...
exit when SUM >= 10000;

end loop;
Cualquier ciclo puede ser nombrado, y cuando un ciclo nombrado es incluido
en el exit, el control es transferido a la sentencia inmediatamente siguiendo lo
referenciado por el ciclo. Por ejemplo, considere el siguiente segmento de
cdigo:
OUTER_LOOP:
for ROW in 1..MAX_ROWS loop
INNER_LOOP:
for COL in 1..MAX_COLS loop
SUM := SUM + MET(ROW, COL);
exit OUTER_LOOP when SUM > 1000.0;
end loop INNER_LOOP;
end loop OUTER_LOOP;
En este ejemplo, el exit es una bifurcacin condicional de la primera sentencia
despus del ciclo externo. Si el exit estaba en cambio
exit when SUM > 1000.0;
esto sera una bifurcacin condicional de la primera sentencia despus del ciclo
interno. Note que las sentencias exit son frecuentemente usados para
manipulacin inusual o condiciones de error.
C, C++, y Pascal tienen innombradas incondicionales (break en C y C++; y last
en Perl); FORTRAN 90 y Java tienen salidas nombradas incondicionalmente
(EXIT en FORTRAN 90 y break en Java), como Ada, excepto que en la versin de
Java el indicador puede estar en cualquier sentencia compuesta encerrada.
C y C++ incluyen un mecanismo de control, continue, que transfiere el control
del mecanismo de control del ms pequeo ciclo encerrado. Esta no esuna
salida sino ms bien una manera para saltar del resto de las sentencias del
ciclo en la actual iteracin sin terminar la estructura del ciclo. Por ejemplo,
considerar lo siguiente:
while (sum < 1000) {
getnext (valor);
if (valor < 0) continue;
sum += valor;
}
Un valor negativo causa la sentencia de asignacin para ser saltado, y el
control se transfiere en cambio al condicional en la cima del ciclo. Por otro lado,
en:

while (sum < 1000) {


getnext (valor);
if (valor < 0) break;
sum += valor;
}
un valor negativo termina el ciclo.
FORTRAN 90, Perl, y Java tienen sentencias similares a continue, excepto que
ellos pueden incluir nombres que especifican que ciclo esta ser continuado.
Ambos exit y break proporcionan salidas mltiples para los ciclos, los cuales
tienen algunos impedimentos a la legibilidad. Sin embargo, las condiciones
inusuales que requieren la terminacin del ciclo son as comunes tal como una
construccin es justificada. Adems, la legibilidad no es un serio perjuicio,
porque el indicador de todos tal como las salidas de ciclos es la primera
sentencia despus del ciclo en lugar de justamente en cualquier lugar en el
programa. El break de Java y el last de Perl son excepciones porque sus
indicadores pueden estar en cualquier sentencia compuesta encerrada.
8.4.4 Estructuras de Datos basadas en Iteracin
Slo un tipo adicional de estructura de ciclo resta ser considerado aqu: la
iteracin que depende de las estructuras de datos. En lugar de tener un
contador o una expresin de control de iteraciones Boolean, estos ciclos se
controlan por elnmero de elementos en una estructura del datos. COMMON
LISP y Perl tienen tales sentencias.
En COMMON LISP, la funcin dolist itera en listas simples que son las
estructuras de datos ms comunes en los programas LISP. Debido a esta
restriccin, el dolist es automtico en el sentido que l siempre implcitamente
itera en los elementos de la lista. Causa la ejecucin de su cuerpo una vez para
cada elemento en la lista dada. La sentencia foreach de Perl es similar; l itera
en los elementos de listas o arrays. Por ejemplo,
@names = (Bob, Carol, Ted, Beelzebub);

foreach $name (@names) {


print $name;
}
Una sentencia de iteracin basado en datos ms general usa estructuras de
datos definidos por el usuario y una funcin definida por el usuario para pasar
por los elementos de la estructura. Esta funcin es llamada iterador. El iterador
es llamado al principio de cada iteracin, y es llamado en cada momento, el
iterador retorna un elemento de una estructura del datos particular en algn
orden especfico. Por ejemplo, suponga un programa que tiene un rbol binario
de nodos de los datos, y el dato en cada nodo deben procesarse en algn
orden particular. Una sentencia de iteracin definida por el usuario para el
rbol pondra consecutivamente el conjunto de variables del ciclo para apuntar
a los nodos en el rbol, uno para cada iteracin. La ejecucin inicial de la
sentencia de iteracin definida por el usuario necesita emitir una llamada

especial al iterador para conseguir el primer elemento del rbol. El iterador


siempre deben recordar qu nodo que present en ltimo lugarpara que visite
todos los nodos sin visitar cualquier nodo ms de una vez. As que un iterador
debe ser la historia sensible. Una sentencia de iteracin definida por el usuario
termina cuando el iterador no encuentra ms elementos.
El constructor for de C, C++, y Java, debido a su gran flexibilidad, puede usarse
para simular una sentencia de iteracin definida por el usuario. Una vez ms,
suponga que los nodos de un rbol binario son para ser procesado. Si la raz del
rbol apunta a una variable nombrada raz, y si el travesao es una funcin
que pone su parmetro para apuntar al prximo elemento de un rbol en el
orden deseado, lo siguiente podra usarse:
for (ptr = root; ptr = = null; traverse(ptr)){

}
En esta sentencia, traverse es el iterador.
Las sentencias de iteracin definidas por el usuario son ms importantes en la
programacin orientada a objetos porque sus paradigmas fueron ms fciles de
desarrollar en software. Este resultado del hecho que el usuario ahora
rutinariamente construya tipos de datos abstractos para las estructuras de
datos. En tales casos, una sentencia de iteracin definida por el usuario y su
iterador deben ser provistos por el autor de la abstraccin de datos porque la
representacin de objetos en los tipos no son conocidas por el usuario. En C+
+, el iterador para el tipo definido por el usuario, o clases, son frecuentemente
implementadas como funciones amigas a las clases o como clases separadas
por el iterador.
8.5 Bifurcacin Incondicional
Una sentencias de bifurcacin incondicional transfiere el control de la ejecucin
a un lugar especficoen el programa.
8.5.1 Problemas con la Bifurcacin Incondicional
El ms acalorado debate en los diseos de los lenguajes de los ltimos 1960
fue sobre problema de si la bifurcacin incondicional debera ser parte de
cualquier lenguaje de alto nivel, y si as es, si su uso debera ser restringido.
La bifurcacin incondicional, o goto, es la sentencia ms poderosa para
controlar l flujo de la ejecucin de las sentencias de un programa. Sin embargo,
usando el goto descuidadamente puede dejar problemas. El goto tiene un
estupendo poder y gran flexibilidad (todas las otras estructuras de control
pueden ser construidas con goto y un seleccionador), pero su mucha fuerza
hace su uso peligroso. Sin restricciones en su uso, impuestos por los diseos
del lenguaje o los estndares de la programacin, las sentencias goto pueden
hacer programas virtualmente ilegibles, y como resultado, sumamente ilegibles
y difciles de mantener.
Estos problemas siguen directamente de la capacidad de un goto de forzar
cualquier sentencia del programa a seguir a cualquier otra en la secuencia de
ejecucin, sin tener en cuenta que si la sentencia precede o sigue el primer

orden textual. La legibilidad es mejor cuando el orden de ejecucin de las


sentencias es cercana al mismo como el orden en el cual ellos aparecen- en
nuestro caso, esto debera significar la cima o el fondo, el cual es el orden para
el cual estn acostumbrados. As que restringiendo los gotos de modo que
puedan transferir el control solo descendentemente en un programa
parcialmente situando el problema. Esto permite a los gotos transferir el
controlalrededor de la seccin de cdigo en respuesta al error o las condiciones
inusuales, pero desaprobando su uso para cualquier clase de ciclo.
Aunque varias precavidas personas los han sugerido tempranamente, fue
Edsger Dijkstra quin dio al mundo informtico la primera amplia lectura
descubriendo el peligro del goto. En su carta noto, La sentencia goto es como
su posicin tambin primitiva; este es tambin mucho ms que una invitacin
a hacer un enredo de unos programas (Dijkstra, 1968a). Durante los primeros
aos despus de la publicacin de la visin de los goto de Dijkstra, un gran
nmero de personas argumentaron pblicamente la expulsin absoluta o por lo
menos la restriccin del goto. Entre estos quienes no favorecan a la completa
eliminacin estaba Donald Knuth, quin argument que estos fueron
ocasionados cuando la eficiencia del goto pesaba ms que su dao a la
legibilidad (Knuth, 1974).
Algunos lenguajes han sido diseados sin un goto por ejemplo, Modula-2 y
Java. Sin embargo, la mayora de los lenguajes populares actuales incluyen una
sentencia goto. Kernighan y Ritchie (1978) llamaron al goto infinitivamente
maltratado, pero es no obstante incluido en el lenguaje C de Ritchie. Los
lenguajes que tienen eliminado el goto tienen suministrado sentencias de
control adicional, usualmente en la forma de ciclos salidas a subprogramas,
reemplaza muchas de las aplicaciones del goto.
Todas las sentencias de salida del ciclo discutidas en la seccin 8.4.3 son
actualmente sentencias camufladas goto. Ellas son, sin embargo, gotos
severamente restringidos y no son dainos a lalegibilidad. De hecho, puede ser
argumentado que ellos mejoran la legibilidad porque evitan que el uso de su
resultado en enroscados e innaturales cdigos pudieran ser mucho ms
difciles de entender.
8.5.2 Formas Nombradas
Algunos lenguajes , como ALGOL 60 y C, usan su forma identificador para sus
nombres. FORTRAN y Pascal usan constantes enteras sin signo para sus
nombres. Ada usa la forma de su identificador como parte del indicador de su
sentencia goto, pero cuando el nombre aparece en una sentencia, este debe
ser delimitado por los smbolos . Por ejemplo, considerar lo siguiente:
goto FINISHED;

SUM := SUM +NEXT;


El delimitador hace los nombres ms fciles de hallar cuando el programa es
ledo. En otros muchos lenguajes, los nombres son adjuntados a las sentencias
por dos puntos, como en

finished: sum := sum + next


En su diseo de nombres, solo PL/I toma otra vez una construccin para su
limite de flexibilidad y complejidad. En lugar de tratando los nombres como
simples constantes, PL/I permite que sean variables. En su forma de variable,
pueden ser asignados valores y usados como parmetros de subprogramas.
Esto permite un goto para ser indicado virtualmente en cualquier parte en un
programa, y el indicador no puede ser estticamente determinado. Aunque su
flexibilidad es algunas veces poderosa, a lo lejos es tambin perjudicial para la
legibilidad valga la pena. Imagine probando leer y entender un programa que
tiene bifurcacin cuyo indicador depende del valor asignado en el tiempo de
ejecucin. Considerar un subprograma que tiene varios nombres y un goto
cuyo nombreindicador es un parmetro formal. Para determinar el indicador del
goto, uno debe conocer la unidad de llamada al programa y el valor del
parmetro actual usado en la llamada. La implementacin de la variable
nombrada es tambin compleja, primariamente porque de todas las posibles
maneras de variables nombradas puede ser un salto al valor.
8.6 Comandos Protegidos
Una alternativa y diferente forma de seleccin estructuras de ciclos fueron
sugeridas por Dijkstra (1975). Su motivacin fue proporcionar sentencias de
control que seran soportadas en una metodologa de diseo de programa que
asegure la correccin durante el desarrollo en lugar de confiar en la verificacin
o chequeo de los programas completados para asegurar su correccin. Esta
metodologa es descripta por Dijkstra (1976).
Los comandos protegidos son cubiertos en este captulo porque ellos son la
base para dos mecanismos lingsticos desarrollados ms tarde para
programacin actual en dos lenguajes, CSP (Hoare, 1978) y Ada.
Concurrentemente es discutido Ada en el captulo 13.
Las construcciones de seleccin de Dijkstra tiene la forma
if ->
[] ->
[]
[] ->
fi
La palabra reservada de cerrado, fi, es la palabra reservada operando
deletreada al revs. Esta forma de palabra reservada de cerrado es tomado de
ALGOL 68. los bloques pequeos, llamados fatbars, son usados para separar la
clusula protegida y permite a la cl
la ser una secuencia de sentencias.
Esta construccin de seleccin tiene la apariencia de una seleccin mltiple,
pero su semntica es diferente. Todas las expresiones Boolean son evaluadas
cadavez que la construccin es alcanzada durante la ejecucin. Si ms de una
expresin es verdadera, una de las sentencias correspondiente es no
determinadamente escogida por ejecucin. Si no es verdadera, un error en

tiempo de ejecucin ocurre que causa el termino del programa. Esto forza al
programador a considerar y listar todas las posibilidades, como con la
sentencia case de Ada. Considerar el siguiente ejemplo:
if i = 0 -> sum := sum +i
[] i > j -> sum := sum + j
[] j > I -> sum := sum + I
fi
Si i =0 y j > i, esta construccin escoge no indeterminadamente entre las
primera y tercera sentencias de asignacin. Si i es igual a j y no es cero, un
error en tiempo de ejecucin ocurre porque ninguna de las condiciones es
verdadera.
Esta construccin puede ser una manera elegante de permitir al programador
condicionar el orden de ejecucin, en algunos casos, es irrelevante. Por
ejemplo, hallar el ms largo de dos nmeros, podemos usar
if x >= y -> max := x
[] y >= x -> max := y
fi
Este cmputo deseado resulta sin sobre especificando la solucin. En
particular, si x y y son iguales, no importa que asignamos a max. Es una forma
de abstraccin proporcionada por la no determinada semntica de la sentencia.
Otra situacin en la cual la construccin de seleccin de Dijsktra es valiosa es
la siguiente: Supongamos que estamos escribiendo un programa que
interrumpe servicios, y el interruptor tiene la misma prioridad. Por esto,
necesitamos una construccin que elija entre interruptores actuales en algunos
maneras aleatorias.
La semntica de los comandos protegidos sondifciles de describir
precisamente. Aunque los diagramas de flujo no son buenas herramientas para
el diseo de programas, son algunas veces poderosas descripciones para las
semntica. La figura 8.1 es un diagrama de flujo describiendo la aproximacin
usada por la sentencia de seleccin de Dijkstra. Note que este diagrama de
flujo es relativamente impreciso, reflejando la dificultad en la captura de la
semntica de los comandos protegidos.
La estructura de ciclo proporcionada por Dijkstra tiene la forma
do ->
[] ->
[]
[] ->
od
La semntica de esta construccin es que todas las expresiones Boolean son
evaluadas en cada iteracin. Si ms de una es verdadera, una de las
sentencias asociadas es no determinadamente escogida por la ejecucin,
despus del cual la expresiones son evaluadas otra vez. Cuando todas las
expresiones son simultneamente falsa, el ciclo termina.
Considerar el siguiente cdigo, el cual aparece en forma ligeramente diferente

en Dijkstra (1975). Las cuatro variables q1, q2, q3, y q4 son para tener su valor
reorganizados para que q1 q3 -> temp := q2; q2 := q3; q3 := temp;
[] q3 > q4 -> temp := q3; q3 := q4; q4 := temp;
od
Un diagrama de flujo describiendo la aproximacin es usada las sentencias de
ciclo de Dijkstra es mostrada en la figura 8.2. Una vez ms, note que la
semntica del flujo de control de esta construccin no puede ser
completamente descripta en un diagrama de flujo.

Figura 8.1
Diagrama de Flujo
aproximado usado con
el seleccionador de
sentencias de Dijkstra
T

FT

Los comandos protegidos por Dijkstra, como estas dos construcciones son
conocidas, son interesante en parte porque ellas ilustran como la sintaxis y la
semntica de las sentencias puede tener un impacto en le verificacin del
programa, y viceversa. La verificacin del programa es virtualmente imposible
cuando las sentencias goto son usadas. La verificacin es muy simplificada si
solo los ciclos lgicos ciclos de seleccin, como los de Pascal, son usados, o los
comandos protegidos son usados. La semntica axiomtica de los comandos
protegidos es convenientemente especificada (Gries, 1981). Debera ser obvio,
sin embargo, aqu es considerablemente incrementada la complejidad en la
implementacin de los comandos protegidos sobre su complemento
determinado convencional.

8.6 Conclusiones
Figura 8.1
Diagrama de Flujo
aproximado usado con
sentencias de ciclo de
Dijkstra

Tenemos descripto y discutido una variedad de niveles de sentencias de


estructuras de control. Una breve evaluacin parece ahora estar en orden.
Primero, tenemos resultados tericamente que solo ciclos de secuencias,
seleccin y lgicos pre examinados son absolutamente requeridos para
expresar clculos. (Bhm y Jacopini, 1966).
Este resultado ha sido ampliamente usado por estos quienes deseaban prohibir
completamente la bifurcacin incondicional. Por supuesto, hay suficientes
problemas prcticos ya con el goto condenndolosin tambin hallar una razn
terica. Una aplicacin del goto que se puede creer es justificada, es su uso
para permitir salidas prematuras de ciclos en lenguajes que no tienen
sentencias de salida.
Un obvio mal uso del resultado de Bhm y Jacopini es argumentar en contra de
la inclusin de todas las estructuras de control ms all de los ciclos pre
examinados lgicos y de seleccin. El lenguaje no ampliamente usado no tiene

todava que tomar este paso; adems, dudamos que todas manden debido al
efecto en la escritura y la legibilidad. Los programas escritos con una sola
seleccin y ciclos pre examinados lgicos son generalmente menos naturales
en estructura, ms complejos, y por lo tanto difciles de escribir y ms difciles
de leer. Por ejemplo, la estructura de seleccin mltiple de Ada es una gran
ganancia para la escritura de Ada, con claros negativos. Otro ejemplo es la
estructura de ciclo contadora de muchos lenguajes, especialmente cuando la
sentencia es simple, como en Pascal y Ada.
No es claro para qu la utilidad de muchas de las otras estructuras de control
que han sido propuestas es mrito de su inclusin en lenguajes (Ledgard y
Marcotty, 1975). Esta cuestin apoya a un largo grado en la cuestin
fundamental de si el tamao de los lenguajes debe ser minimizado. Ambos,
Wirth (1975) y Hoare (1973), fuertemente avalaron la simplicidad en el diseo
del lenguaje. En el caso de las estructuras de control, la simplicidad significa
que solo algunas sentencias de control deberan estar en el lenguaje, y todas
ellas deberan ser simples.
La rica variedad de niveles de sentencias deestructuras de control que han sido
inventadas muestran la diversidad de opiniones entre los diseadores del
lenguaje. Despus de todo el invento, la discusin, y la evaluacin, no hay
todava unanimidad de opinin en el preciso conjunto de sentencias de control
que deberan estar en un lenguaje. Muchos lenguajes contemporneos, por
supuesto, tienen sentencias de control similar, pero hay todava algunas
variaciones en los detalles de su sintaxis y semntica. Adems, hay todava
desacuerdo en si un lenguaje debera incluir un goto; C++ y Ada 95 lo hacen,
pero Java no.
Una nota final: Las estructuras de control de lenguajes de programacin
funcional y lgica y Smalltalk son todas bastante diferentes de estas descriptas
en este captulo. Estos mecanismos son discutidos en algunos detalles en el
Captulo 15, 16, y 12, respectivamente.
Resumen
Las sentencias de control de los lenguajes imperativos suceden en varias
categoras: seleccin, seleccin mltiple, iterativa, y bifurcacin incondicional.
FORTRAN introdujo un seleccionador de sentencia de una manera, el lgico IF.
El seleccionador de ALGOL 60 es ms avanzado, permitiendo la seleccin de
sentencias compuestas e incluyendo un clusula opcional else. Muchas
estructuras de control se beneficiaron de las sentencias compuestas que
ALGOL 60 introdujo.
El IF aritmtico de FORTRAN es seleccionador de tres maneras que usualmente
requiere otra bifurcacin incondicional.
FORTRAN introdujo dos formas de sentencias de seleccin mltiple: el calculado
GO TO y el asignado GO TO . Cierto a sus nombres, ambos son
actualmenteramificaciones de manera mltiple. El case de Pascal es
representativo de modernas sentencias de seleccin mltiple; incluye ambos,
encapsulacin de segmentos seleccionables y ramificaciones implcitas en el

final de cada punto nico de salida.


Un nmero largo de diferentes sentencias ciclos han sido inventadas por los
lenguajes de alto nivel, comenzando con el contador de FORTRAN DO. La
sentencia for de ALGOL 60 fue tambin complejo, combinando controles
contadores y lgicos en una sola sentencia. La sentencia for de Pascal es, en
trminos de complejidad, lo opuesto. Elegantemente implementa solo la forma
ms comnmente necesaria de contar ciclos. La sentencia for de C es la
construccin iterativa ms flexible.
C, C++, FORTRAN 90, Java, Perl, y Ada tienen sentencias de salida para sus
ciclos, estas sentencias toman el lugar de uno de los ms comunes usos de la
sentencias goto.
Los iteradores basado en datos son construcciones de ciclos para procesar
estructuras de datos, como las listas enlazadas, hashes, y rboles.
La bifurcacin incondicional, o goto, ha sido parte de muchos lenguajes
imperativos. Sus problemas han sido ampliamente discutidos y debatidos. El
actual consenso es que debera permanecer en ms lenguajes pero su perjuicio
debera ser minimizado a travs de disciplinas de programacin.
Los comandos protegidos de Dijkstra son construcciones de control alternativa
con caractersticas tericas emntica aparece en los actuales mecanismos de
CSP y Ada.
positivas. Aunque ellas no han sido adoptadas como construcciones de control
de un lenguajes, parte de la s

Das könnte Ihnen auch gefallen