Capítulo 7. Abstracciones (subprogramas).

Anuncio
Capítulo 7. Abstracciones (subprogramas).
Lenguajes de Programación
Carlos Ureña Almagro
Curso 2011-12
Contents
1 Introducción
2
2 Procedimientos
3
3 Funciones
6
4 Parámetros
12
4.1
Mecanismos de paso de parámetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
4.2
Mecanismos en Ada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
4.3
Mecanismos en C/C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
4.4
Mecanismos en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
4.5
Mecanismos en C# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
5 Efectos laterales
20
6 Orden de evaluación
21
6.1
Operadores o funciones no estrictas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
22
1
1
INTRODUCCIÓN
Introducción
El concepto de abstracción
En general, una abstracción es un cálculo (asociado a un nombre) que puede ser utilizado en distintas partes
de un programa.
Se llama abstracción porque el programador puede usarla abstrayéndose de cómo se lleva a cabo el cálculo,
y centrándose en que efectos tiene.
Ventajas de las abstracciones
Las abstracciones son esenciales para:
• Mejorar la legibilidad: permite programas más cortos, más simples.
• Mejorar la facilidad de escritura: permite trasladar más fácilmente los diseños a código.
• Permitir o facilitar la reusabilidad.
• Particionar los programas, disminuyendo la cohesión.
• Facilitar el trabajo en equipo.
Tipos de abstracciones
Las abstracciones se pueden clasificar en base al tipo de cálculo asociado, aquí veremos estos dos tipos:
• Abstracciones procedurales (procedimientos): el cálculo es la ejecución de una determinada sentencia.
Constituyen abstracciones sobre sentencias.
• Abstracciones funcionales (funciones): el cálculo es la evaluación de una determinada expresión.
Constituyen abstracciones sobre expresiones.
Declaración de abstracciones
Las abstracciones pueden verse como asociaciones entre un nombre y el cálculo correspondiente.
• Para establecer esta asociación es necesario escribir un declaración.
• En la declaración se especifica el nombre de la abstracción y el cálculo asociado.
2
2
2
PROCEDIMIENTOS
Procedimientos
El concepto de procedimiento
Una procedimiento es, en general, una abstracción sobre una orden.
• Un procedimiento tiene asociado un nombre. Esta asociación se produce mediante una declaración.
• El nombre del procedimiento se puede usar (en el ámbito de su declaración) como una orden más. A
estas apariciones del nombre se les denomina llamadas al procedimiento
Declaración de procedimiento
Una declaración de un procedimiento es un tipo de declaración que crea el procedimiento y le da un nombre.
Consta de:
• El nombre del procedimiento (un identificador: id)
• Los parámetros formales (opcionalmente)
• La sentencia asociada (posiblemente compuesta, y con declaraciones locales) (la llamaremos O).
Declaraciones de procedimientos.
• En el ámbito de la declaración, id se puede usar como una orden, completamente equivalente a O
• A la orden O se le suele llamar el cuerpo del procedimiento.
• La elaboración de la declaración no suele conllevar ningún procesamiento en tiempo de ejecución,
excepto en lenguajes interpretados
Declaraciones de procedimientos.
Supongamos una declaración de un procedimiento con estos elementos:
• Nombre: actumax
• Sentencia: O =
if ( x > y ) max = x ; else max = y ;
• Esta declaración debe aparecer en el ámbito de la declaración de max, x e y
• En el ámbito de la declaración, el identificador actumax() se puede usar como una sentencia,
equivalente a la sentencia if
3
2
PROCEDIMIENTOS
Llamadas a procedimientos
En el ámbito de la declaración, se puede escribir actumax() como una sentencia más, siendo equivalente
a su sustitución por el cuerpo del procedimiento:
Estas sentencias:
Son equiv. a estas:
x = 1 ;
y = 2 ;
actumax ( ) ;
x = 1 ;
y = 2 ;
i f ( x > y ) max = x ;
e l s e max = y ;
z = max ;
z = max ;
Declaraciones de procedimientos en Ada
En Ada, la declaración de procedimientos es un tipo de declaración que puede aparecer en el lugar de
cualquier declaración de variables o tipos, su sintaxis es esta:
p r o c e d u r e ident [ parametros ] i s
[ declaraciones ]
begin
ordenes
end [ ident ] ;
• Los parámetros y las declaraciones son opcionales,
• La orden es obligatoria (puede ser skip, que no hace nada).
Declaraciones de procedimientos en C/C++/C#/Java
En estos lenguajes, las declaraciones de procedimientos son como cualquier otra declaración, excepto que
no pueden aparecer dentro de una declaración de procedimiento o función.
v o i d ident ( [ parametros ] )
{
[ declaraciones − y − ordenes ]
}
• Los parámetros, las ordenes y/o las declaraciones son opcionales
• La paréntesis son obligatorios
Declaraciones de procedimientos en Python
En este lenguaje, la declaración de un procedimiento es un tipo de sentencia
4
2
PROCEDIMIENTOS
• Cuando se ejecuta la sentencia de declaración, se asocia el identificador a la sentencia o sentencias
que forman el cuerpo. a partir de ese momento, el identificador es usable para llamar al procedimiento
• El ámbito de la declaración de subprogramas es similar al de las variables:
– una declaración de un subprograma P, incluida en el cuerpo de un subprograma Q, es local a Q
(se destruye al acabar Q)
– una declaración de un subpr. no incluida en otro es global: permanece hasta el final del programa
(o hasta que se haga otra asociación al identificador)
Declaraciones de procedimientos en Python
Hay dos sintaxis posible, una es en una sola línea:
d e f ident ( [ parametros ] ) : orden
o en varias:
d e f ident ( [ parametros ] ) :
orden1
orden2
···
ordenn
Declaraciones de procedimientos en Python
Respecto a la sintaxis anterior:
• En la segunda forma, la sentencias que forman el cuerpo son todas aquellas con indentación superior
a la indentación de def
• al menos debe haber una sentencia en el cuerpo
• La construcción puede aparecer en el lugar de cualquier sentencia
• Es importante tener en cuenta que un identificador asociado a una función puede asociarse a otra
función o a una variable en cualquier momento, lo cual puede lugar a errores
Asociación dinámica parcial en Python
En Python, los identificadores libres del cuerpo se interpretan en el entorno formado por las variables
globales existentes en la llamada, excluyendose las locales
• Se puede considerar una forma de asociación dinámica no completa, o asociación dinámica parcial
• El comportamiento puede ser inesperado a veces
5
3
FUNCIONES
Asociación dinámica limitada en Python
Este ejemplo ilustra como se interpretan los identificadores libres en el cuerpo de un subprograma:
def escribe_zz ( ) :
p r i n t zz
def llamar_escribe_zz ( ) :
zz = ( 4 , 4 , 4 , 4 )
escribe_zz ()
l l a m a r _ e s c r i b e _ z z ( ) # e r r o r ( no e x i s t e ’ z z ’ )
z z =1; l l a m a r _ e s c r i b e _ z z ( ) # e s c r i b e " 1 "
z z=" h o l a " ; l l a m a r _ e s c r i b e _ z z ( ) # e s c r i b e " h o l a "
Ejemplo de declaración de procedimiento en Python
El siguiente es un ejemplo que ilustra el hecho de que las declaraciones de procedimientos son sentencias,
y por tanto un identificador puede asociarse a distintos subprogramas en distintas ejecuciones (o incluso en
una ejecución)
x = ...
y = ...
if x > y :
def proce ( ) : p r i n t " hola "
else :
def proce ( ) : p r i n t " adios "
proce ( )
def proce ( ) : x = 2
3
# ok : r e d e f i n e ’ p r o c e ’
Funciones
El concepto de función
• Una función es, en general, una abstracción sobre un proceso de cálculo que produce un valor único
como resultado (cada vez que se realiza dicho proceso de cálculo). También se le llama en la literatura
abstracción funcional.
• Una función tiene asociado un nombre. Esta asociación se produce mediante una declaración.
• El nombre de la función se puede usar como una expresión más (en el ámbito de su declaración)
• También se le llaman abstracciones funcionales
6
3
FUNCIONES
Funciones en los paradigmas funcional e imperativo
• En los lenguajes funcionales, una función es una abstracción sobre una expresión (el proceso de cálculo
es la evaluación de la expresión).
• En los lenguajes imperativos, un función es una abstracción sobre un tipo especial de orden que produce
un valor resultado (el proceso de cálculo es la ejecución de dicha orden para obtener el valor).
El término función
• El término función hace referencia a un determinado cálculo, completamente distinto a una función
matemática, aplicación, o correspondencia (que es un tipo especial de relación entre elementos de dos
conjuntos matemáticos)
• En un programa, las abstracciones funcionales son la forma natural implementar las funciones matemáticas
Órdenes que producen un resultado.
• En algunos lenguajes (p.ej. Eiffel, Pascal), estas órdenes incluyen necesariamente una asignación a
una variable local especial que almacena el resultado.
• Esta variable local no está declarada implicitamente
• En Pascal, su nombre coincide con el de la función
• Al finalizar la ejecución de la orden, el valor de dicha variable es el valor resultado.
Órdenes que producen un resultado.
• En otros lenguajes (Ada,C/C++, Java, C#) estas órdenes incluyen necesariamente una orden especial:
return e
• Aquí, e es una expresión del mismo tipo que la función
• La ejecución de la órden return e dentro de una orden (posiblemente compuesta) O supone:
– La evaluación de e y la obtención de un valor v
– La finalización de la ejecución de O, con v como valor resultado.
7
3
FUNCIONES
Declaraciones de funciones
Una declaración de una función es un tipo de declaración que crea la función y le da un nombre.
• La declaración permite escribir la expresión u orden una vez, pero usarla varias veces como una
expresión en distintos puntos del programa.
• Usar la expresión u orden quiere decir aquí evaluar la expresión (o ejecutar la orden) para obtener un
valor. A esto se suele denominar llamar o invocar a la función.
Elementos de las declaraciones de funciones:
La declaración de una función consta de:
• El nombre de la función (un identificador ident)
• El nombre (o descriptor en algunos casos) del tipo del valor resultado, referenciando un tipo T
• Los parámetros formales (opcionalmente).
• Una expresión e o una sentencia que produce un valor O
Declaraciones de funciones
• En el ámbito de la declaración, id se puede usar como una expresión, completamente equivalente a e
• A la expresión e o a la orden O se les suele llamar el cuerpo de la función.
• La elaboración de la declaración no suele conllevar ningún procesamiento.
Ejemplo de declaración de una función
(supone asociación estática)
• El identificador es difxy
• La expresión que forma el cuerpo es x-y (si el cuerpo estuviese formado por una sentencia, seria x-y)
• La declaración debe aparecer en el ámbito de la declaración de x e y
• En su ámbito, difxy() constituye una expresión equivalente a la expresión x-y
8
3
FUNCIONES
Llamadas a funciones.
En el ámbito de la declaración, se puede escribir difxy() como una expresión más, siendo equivalente a
su sustitución por x-y
Estas sentencias:
Son equiv. a estas:
x = z ;
y = 2 ∗ h ;
z = h ∗ difxy () + 3 ;
x = z ;
y = 2 ∗ h ;
z = h ∗ (x − y) + 3 ;
Ejemplo de función con una órden
Supongamos que ahora el cuerpo de una función area es una orden, como por ejemplo c=c+1 ; return
2*pi*r ;
Estas sentencias:
Son equiv. a estas:
r = 35.67 ;
a = ( k +10.0)∗ area ( ) + 1 ;
r = 35.67 ;
tmp1 = k +10.0
c = c+1 ;
tmp2 = 2∗ p i ∗ r ;
a = tmp1 ∗ tmp2 +1;
.
Declaraciones de funciones en Ada
La forma de estas declaraciones (que pueden aparecer donde cualquier declaración de variable o tipos) es:
f u n c t i o n ident [ parametros ] r e t u r n identtipo i s
[ declaraciones ]
begin
ordenes
end [ ident ] ;
• El tipo devuelto no puede ser anónimo
• Los parámetros y las declaraciones son opcionales,
• La orden es obligatoria, y debe incluir return
Declaraciones de procedimientos en C/C++/C#/Java
En estos lenguajes, la declaración puede aparecer en el lugar de una declaración de variable o tipo, excepto
dentro de otro subprograma.
9
3
FUNCIONES
descriptortipo ident ( [ parametros ] )
{
[ declaraciones − y − ordenes ]
}
• Los parámetros, las ordenes y/o las declaraciones son opcionales.
• Los paréntesis son obligatorios
• La orden puede incluir return
Declaraciones de funciones en Python
En este lenguaje, no se distingue entre procedimientos y funciones, sino que simplemente contempla declaraciones de subprogramas en general.
• Por tanto, la sintaxis usada para declarar subprogramas es la que ya vimos para los procedimientos.
• Cualquier declaración de subprograma puede incluir sentencias return.
• Si un subprograma siempre acaba con un return de un valor de un tipo concreto T podemos ver ese
subprograma como una función de tipo T.
Declaraciones de funciones en Python
• En distintas ejecuciones de un subprograma, pueden ejecutarse sentencias return con expresiones de
tipos distintos, o no ejecutarse ningun return en absoluto (el subprograma acaba como los procedimientos)
• Por tanto, el intérprete no puede asignar un tipo a un subprograma, ni clasificarlo como procedimiento
o función, aún cuando eventualmente devuelva un valor via un return (las "funciones" no tienen asociado
un tipo).
Llamadas a subprogramas en Python
Se puede escribir una llamada a un subprograma en el lugar de una expresión o en el de una sentencia
• Una llamada que no acaba con return y que se usa como expresión produce el valor None de tipo
NoneType.
• Una llamada que acaba con return y que se usa como sentencia implica que el valor resultado se
ignora (no se almacena en ningún sitio).
10
3
FUNCIONES
Funciones lambda en Python
Al igual que muchos lenguajes funcionales, el lenguaje Python permite escribir expresiones de tipo función.
• Estas expresiones, al evaluarse, producen como resultado una función. A estas funciones se les suele
llamar funciones lambda
• Las funciones así obtenidas son anónimas, ya que no tienen asociado un nombre
• Estas funciones pueden almacenarse en variables o parámetros (que serán entonces de tipo función),
de forma que pueden ser invocadas usando el nombre de la variable o el parámetro
Expresiones de tipo ’función lambda’
La sintaxis de estas expresiones es como sigue:
lambda [ parametros ] : expresion
• Al evaluarse, estas expresiones producen como resultado una función (o mas exactamente, una referencia
a una función), cuyo cuerpo es la expresión que se indique.
• Pueden aparece en tres contextos:
– a la izquierda de los parámetros actuales a los que se va a aplicar
– a la derecha de una asignación
– en una lista de parámetros actuales.
Ejemplo de expresiones de tipo ’función lambda’
Aquí hay ejemplos de funciones lambda (sin parámetros)
p r i n t ( lambda : " h o l a "
# e s c r i b e " hola "
)()
x = 2 ; y = 3
p r i n t 4+2∗( lambda : x ∗y ) ( ) − 1
# escribe ’15 ’
x = 4 ; y = 4
f = lambda : x+y+2
p r i n t 2∗ f ( ) + 3
# escribe ’23 ’
11
4
4
PARÁMETROS
Parámetros
Utilidad de los parámetros
En la forma descrita, los subprogramas leen o modifican siempre las mismas variables.
• Si queremos que un subprograma actué sobre distintas variables, debemos de usar unas variables
especificas asociadas al subprograma.
• Dichas variables deben ser inicializadas antes de la llamada, y/o leídas después de la misma
Utilidad de los parámetros
Ejemplo: guardar en una variable entera (c) el máximo de otras dos (a y b)
x = a ; y = b ;
// inicializacion
actumax ( ) ;
c = max ;
/ / lectura del resultado
Aquí, actumax se define supone definifo como en las transparencias anteriores.
Utilidad de los parámetros
Otro ejemplo es una función de nombre maximo para calcular el máximo de dos variables enteras, de nombres
x e y. El cuerpo de la función es la siguiente sentencia (escrita en C/C++)
return y < x ? x : y ;
Un ejemplo de uso sería el siguiente:
x = a ;
y = b ;
d = 2∗ maximo + 1 ;
return y < x ? x : y ;
Utilidad de los parámetros.
En los ejemplos anteriores, x,y y max se usan como variables ligadas al procedimiento actumax, mientras
que x e y, además, también esta ligadas a la función maximo. Hay que tener en cuenta que, respecto a
estas variables:
• su ámbito debe incluir tanto declaración de actumax como la llamada a dicho procedimiento
• la escritura/lectura añade sentencias al programa (lo hace más complejo).
• no deberían ser usadas fuera del subprograma.
12
4
PARÁMETROS
Utilidad de los parámetros.
Para poder hacer esto de forma más simple, evitando los problemas descritos, se diseñó e implementó el
concepto de parámetros de los subprogramas.
El concepto de parámetros.
Los parámetros son variables o valores (constantes) locales a la orden o a la expresión incluida en el cuerpo
de la definición de un subprograma.
• La inicialización se hace en la llamada al subprograma, incluyéndose las expresiones adecuadas.
• La lectura de los resultados se hace al finalizar el subprograma
Ventajas de los parámetros.
El uso de parámetros hace a los programas más simples, legibles, escribibles y fiables, ya que, al usarlos:
• No es necesario escribir explícitamente las asignaciones al inicio o al final (el programa es más legible
y más corto)
• Al ser locales al subprograma, no hay que preocuparse por el ámbito de los parámetros (mas flexibilidad)
• No es posible usar los parámetros fuera del subprograma (menos errores por colisiones de nombres)
Parámetros formales y parámetros actuales
• A las variables (o constentes) locales se les denomina parámetros formales
• Al igual que las variables o constantes, cada parámetro tiene asociado un nombre (y, en muchos
lenguajes, un tipo).
• A las expresiones de inicialización incluidas en la llamada, se les denomina parámetros actuales
• Los parámetros actuales, cuando sirven para recoger un resultado al final, deben ser accesos a variables.
Llamadas a subprogramas con parámetros:
• En la llamada, se especifican los parámetros actuales
• En la inmensa mayoría de los lenguajes, los parámetros actuales se incluyen entre paréntesis tras el
nombre del subprograma, separados por comas.
• En algunos pocos lenguajes (p.ej. Ada), los parámetros actuales pueden estar precedidos por el nombre
del parámetro formal
13
4.1
Mecanismos de paso de parámetros
4
PARÁMETROS
Ejemplo de función con parámetros
La función maximo que hemos visto antes se puede definir con dos parámetros, que sirven para "recoger" los
valores sobre los que se quiere calcular el máximo de ellos.
• Los parametros serán de nombre px y py, y de tipo entero
• El cuerpo de la función será la sentencia: return px > py ?
px :
py ;
Ejemplo de función con parámetros
La orden:
z = maximo ( h +1 , 3 ) + 1 ;
es equivalente a esta otra orden:
i n t tmp ;
{
i n t px = h +1 , py = 3 ;
tmp = px > py ? px : py ;
}
z = tmp + 1 ;
las variables locales px y py (son los parametros formaes) se destruyen al acabar el bloque (ya que están en
el stack). La variable (también local) tmp se usa exclusivamente para almacenar temporalmente el resultado.
4.1
Mecanismos de paso de parámetros
Mecanismos de paso de parámetros
• Existen varias alternativas posibles para interpretar la declaración de parámetros formales, como
declaraciones de constantes o variables locales al cuerpo de la función.
• A las distintas formas se les denomina mecanismos de paso de parámetros.
• En concreto, un parámetro formal puede ser:
1. Una constante
2. Una variable (que no es una referencia)
3. Una variable de un tipo referencia
14
4.2
Mecanismos en Ada
4
PARÁMETROS
Mecanismos de parámetros: 1. Paso por copia
En los casos en los que el parámetro formal es una variable local (no referencia), se crea una variable local
al cuerpo, se le llama paso por copia, y, a su vez, hay varias opciones:
(1.a) La variable local se inicializa al comienzo con el resultado de evaluar el parámetro actual. Se denomina
paso por copia de valor.
(1.b) La variable no se inicializa a la entrada, pero su valor al final se copia sobre el parámetro actual (que
en este caso debe ser un acceso a una variable). Se denomina paso por copia de resultado
(1.c) Se incializa al inicio y se copia al final (tambien aquí el parametro actual debe ser una referencia a
una variable). Se llama paso por copia de valor-resultado
Mecanismos de parámetros: 2. Paso por constante
En otros casos, la entidad declarada localmente es una constante, luego el identificador local esta asociado,
en cada llamada, al valor resultado de evaluar el correspondiente parámetro actual. Se le llama paso por
constante) y se puede implementar de dos formas semánticamente equivalentes:
(2.a) Copiando el valor a una variable local de solo lectura (esto se suele hacer para tipos primitivos)
(2.b) Copiando una referencia a una zona de memoria con el valor u objeto especificado en el parámetro
actual (se suele usar para tipos array, registros, o tipos-referencia en general). Los accessos (de
lectura) se hacen implicitamente vía esa referencia.
Mecanismos de parámetros: 3. Paso por referencia
Otra posibilidad es que el parámetro formal sea una referencia a otra variable de un tipo fijo. Este mecanismo
se denomina paso por referencia.
• El parámetro actual tiene que ser forzosamente un acceso a una variable.
• Es el mecanismo que se usa para los tipos-referencia en los lenguajes que los contemplan (Java/C#)
• La referencia es una variable local que puede ser:
(3.a) modificable (puede pasar referenciar a otras variables distintas del parámetro actual)
(3.b) no modificable (referencia siempre al parámetro actual)
4.2
Mecanismos en Ada
Paso de parámetros en Ada
Por copia de resultado (caso 1.b), o copia de valor-resultado (1.c)
15
4.2
Mecanismos en Ada
4
PARÁMETROS
ident : o u t nombre_tipo ; −− c o p i a de r e s u l t .
ident : i n o u t nombre_tipo ; −− c o p i a de v a l o r − r e s u l t .
• nombre_tipo es un nombre de un tipo primitivo (no referencias) existente
Paso de parámetros en Ada
Por constante (caso 2)
ident : nombre_tipo ;
ident : i n nombre_tipo ;
• nombre_tipo es un nombre de un tipo cualquiera existente (no referencias)
• si nombre_tipo es un tipo primitivo, se usa el esquema (2.a)
• si nombre_tipo es registro o array, se usa (2.b)
Paso de parámetros en Ada
Por referencia (caso 3.b), para tipos access (hay dos posibilidades)
ident : a c c e s s nombre_tipo ;
ident : nombre_tipo_access ;
• nombre_tipo_re f erencia es un nombre de un tipo referencia (access) previamente declarado,
• nombre_tipo es cualquier tipo primitivo: en este segundo caso
– el parámetro actual no puede ser la referencia nula
– se crea un tipo anónimo nuevo, local al subprograma.
Paso de parámetros en Ada
Por referencia (caso 3.b), para tipos registro o array
ident : o u t nombre_tipo ;
ident : i n o u t nombre_tipo ;
• nombre_tipo es el nombre de un tipo array o registro
• ambas formas son equivalentes
• esto fue fijado en Ada 95 (en Ada 83 había cierta ambigüedad en esto).
16
4.3
Mecanismos en C/C++
4.3
4
PARÁMETROS
Mecanismos en C/C++
Paso de parámetros en C/C++
Los mecanismos de paso son más sencillos, ya que:
• La sintáxis y semántica de la declaración de parámetros es exactamente igual a la sintaxis y semántica
de la declaración de variables (se cumple estrictamente el principio de correspondencia)
• En todos los casos, una declaración de un parámetro es equivalente a una declaración local de una
variable o constante con la misma sintaxis
• No existe copia de resultado (1.b) ni copia de valor-resultado (1.c)
• El paso por referencia se hace con punteros o referencias-C++
Paso por copia de valor en C/C++
La siguiente declaración de parámetro en C/C++
nombre_tipo_prim ident ,
supone paso por copia de valor (1.a), aquí nombre_tipo_ident es el nombre o alias de algún tipo primitivo
Paso por referencia en C/C++
Este mecanismo puede obtener mediante alguna de estas declaraciones de parámetros:
tipo
tipo
tipo
tipo
∗ ident / / c a s o ( 3 . a )
∗ c o n s t ident / / c a s o ( 3 . b )
& ident / / c a s o ( 3 . b ) −− r e f . no n u l a
ident [ [ expresion ] ] / / c a s o ( 3 . b )
Paso por constante en C/C++
Al igual que para las variables, los parámetros constantes se declaran anteponiendo const al descriptor de
tipo.
Hay estas formas:
const
const
const
const
const
tipo
tipo
tipo
tipo
tipo
ident / / c a s o ( 2 . a )
∗ ident / / c a s o ( 2 . b )
∗ c o n s t ident / / c a s o ( 2 . b )
& ident / / c a s o ( 2 . b ) ( r e f . no n u l a )
ident [ [ expresion ] ] / / c a s o ( 2 . b )
17
4.4
4.4
Mecanismos en Java
4
PARÁMETROS
Mecanismos en Java
Paso de parámetros en Java
En este lenguaje solo hay dos posibilidades:
• Los tipos-valor se pasan por copia de valor
• Los tipos-referencia se pasan por copia de referencia
• No existe paso por copia de resultado ni valor-resultado
• No existe paso por constante
Al igual que en C/C++, las declaraciones de parámetros son (sintáctica y semánticamnte) semejantes a las
declaraciones de variables.
4.5
Mecanismos en C#
Paso de parámetros en C#
El esquema es similar al de Java, pero además:
• Los tipos-valor se pueden pasar por referencia si se indica explícitamente
• Existen dos formas de paso por referencia de tipos-valor
– una se corresponde con la habitual de otros lenguajes
– otra sirve específicamente para paso por referencia de parámetros de salida (parámetros con
resultados), en los cuales no es posible leer el valor inicial de entrada
Mecanismos de paso de parámetros en C#
Paso por copia de valor.
nombre_tipo_valor ident ,
Se crea una variable local, modificable.
Mecanismos de paso de parámetros en C#
Paso por referencia. Existen estas posibilidades:
nombre_tipo_re f i d ,
nombre_tipo [ ] i d ,
r e f nombre_tipo_valor ident ,
o u t nombre_tipo_valor ident ,
18
4.5
Mecanismos en C#
4
PARÁMETROS
Si se usan las dos últimas formas, es necesario incluir ref u out en la llamada, precediendo al parámetro
actual. Esto mejora la legibilidad.
Mecanismos de paso de parámetros en C#
Paso por referencia de salida
Cuando se usa la forma:
o u t nombre_tipo_valor ident ,
• ident constituye una referencia local a una variable v con un valor que se considera indeterminado a
la entrada
• en el subprograma, el parámetro no se puede leer si no es en sentencias que siguan a alguna asignación
al mismo.
Mecanismos de paso de parámetros en Python
• En Python, los subprogramas y las funciones lambda admiten parámetros formales
• Los parámetros formales (al igual que las variables) no tienen asociado un tipo (el tipo del parámetro
actual y, por tanto, el del valor que se pasa pueden ser distinto en cada llamada)
• Para tipos inmutables (cadenas, números, tuplas) : se pasa una referencia al valor resultado de evaluar el parámetro formal. Dicho valor en memoria no es modificable, así que el mecanismo puede
considerarse como una forma de paso por constante implementada con referencias (caso 2.b).
• Para tipos mutables (listas, diccionarios, clases) : el paso es por referencia a todos los efectos, se
puede modificar la variable referenciada, con efectos permanentes, o bien usar la referencia local para
apuntar a otro valor (caso 3.a).
Valores inmutables como parámetros en Python
Cuando se usa como parámetro actual un valor de tipos inmutables en una llamada a un subprograma:
• El parámetro formal es (en esa llamada) una referencia local que puede usarse para apuntar a otro
valor mediante una asignación a la misma de dicho nuevo valor
• El nuevo valor estará almacenado en otra localización de memoria, el original no se modifica.
• Por tanto, estas modificaciones no afectan al parámetro actual (no tiene efectos a la salida).
19
5
EFECTOS LATERALES
Ejemplo de valores inmutables como parámetros en Python
Este ejemplo ilustra como funciona el paso de parámetros inmutables:
def incrementa ( n ) :
n = n + 1
print n
incrementa (10)
m = 20
i n c r e m e n t a (m)
print m
5
## e s c r i b e
’11 ’
## e s c r i b e
## e s c r i b e
’21 ’
’20 ’
Efectos laterales
Efectos laterales en expresiones y funciones
• Un efecto lateral en una expresión cuando ocurre cuando difieren los estados de ejecución previo
y posterior a la evaluación de la expresión (es decir, se han modificado, creado o destruido alguna
variable)
• Si la expresión es el cuerpo de una función, diremos que la función tiene efectos laterales.
• La funciones con efectos laterales actúan, además de como expresiones, como órdenes
Desventajas de los efectos laterales
Los efectos laterales:
• Disminuyen la legibilidad de los programas
• Desvirtúan el concepto de función, que tiende a confundirse con el de procedimiento.
• Hacen incorrectas ciertas premisas, por ejemplo la conmutatividad de la suma: si f y g son funciones
enteras (sin parámetros) con efectos laterales, la expresión f () + g() no es necesariamente equivalente
g() + f ()
• Impiden ciertas optimizaciones, como, por ejemplo, si e es una expresión de tipo entero con efectos
laterales, e + e no puede sustituirse por 2 ∗ e
Evitar efectos laterales
Los efectos laterales:
• Deben ser evitados por el programador, mejorando así la legibilidad y fiabilidad de los programas
20
6
ORDEN DE EVALUACIÓN
• No pueden ser detectados en un programa (ni siquiera ejecutándolo) por un procesador de un lenguaje
imperativo, excepto en casos triviales
6
Orden de evaluación
Los ordenes de evaluación son distintas formas de decidir cuando se evalúa un operando o un parámetro
formal durante la evaluación de una expresión. Hay tres posibilidades:
• Orden ambicioso
• Orden normal
• Orden perezoso
Orden ambicioso
Por lo descrito hasta ahora:
• La evaluación de una expresión e1 ope2 supone la evaluación de e1 y e2 antes de realizar el cálculo
asociado al operador op
• La evaluación de un expresión de llamada f (e1 , e2 ) supone la evaluación de e1 y e2 antes de realizar
el calculo asociado a la función de nombre f
A esto se le llama evaluación ambiciosa de las expresiones o funciones (eager evaluation)
Evaluación en orden normal
Otra posibilidad es la evaluación en orden normal
• La evaluación de una expresión e1 ope2 supone la evaluación de e1 y/o e2 cada vez que sea necesario
durante el calculo asociado al operador op
• La evaluación de un sentencia de llamada f (e1 , e2 ) supone la evaluación de e1 y e2 cada vez que se
acceda al valor del correspondiente parámetro formal dentro del cuerpo de la función
Evaluación en orden normal
• puede ocurrir que durante la evaluación de una expresión, algún parámetro actual y/o algún operando
no llegue a ser evaluado (no es posible con el orden ambicioso).
• el uso de memoria y el tiempo de calculo puede diferir respecto del orden ambicioso
21
6.1
Operadores o funciones no estrictas
6
ORDEN DE EVALUACIÓN
Orden perezoso
Una tercera posibilidad es la evaluación en orden perezoso (lazy evaluation)
• Es similar a la evaluación en orden normal, excepto que tras la primera evaluación de un parámetro
formal u operando, el valor obtenido se almacena y se usa de nuevo en futuras referencias, durante el
cálculo.
• Constituye una opción intermedia entre las dos formas anteriores.
Orden perezoso
Características de la evaluación en orden perezoso
• Al igual que el orden normal, la evaluación no ocurre necesariamente siempre.
• Al igual que el orden ambicioso, el parámetro actual o el operando se evalúan una sola vez como
mucho.
Equivalencia de órdenes de evlauación
Los tres ordenes no son equivalentes.
Supongamos la siguiente declaración de dos funciones en C
int c = 0 ;
int f ()
{ c=c+1 ; r e t u r n c
; }
i n t g ( i n t a ) { c=1
; r e t u r n a+a ; }
Equivalencia de órdenes de evlauación
Los tres ordenes de evaluación no son equivalentes.
La evaluación de g(f()) usando cada orden de evaluación produciría:
• orden ambicioso : 2 ( f se evalúa una vez, con c==0, a vale 1)
• orden perezoso: 4 ( f se evalúa una vez, con c==1, a vale 2)
• orden normal: 5 ( f se evalúa dos veces, con c == 1 y 2, a vale 2 y 3)
6.1
Operadores o funciones no estrictas
Operadores y funciones no estrictas
22
6.1
Operadores o funciones no estrictas
6
ORDEN DE EVALUACIÓN
Operadores y funciones no estrictas en alguno de sus parámetros u operandos
Se dice que una función u operador es no estricto en alguno de sus parámetros u operandos si la evaluación
de una llamada a la función o al operador puede llevarse a cabo en algunos casos sin evaluar dicho parámetro
u operando
El operador and then
Este es un operador binario lógico con dos operandos lógicos, parecido a and , pero no exactamente igual.
Evaluar e1 and then e2 supone evaluar e1 , y después
• si el resultado es f alse, la evaluación acaba con el valor f alse,
• si el resultado es true, se evalúa e2 , obteniéndose el valor b. La evaluación acaba con el valor b como
resultado
El operador or else
Este es un operador binario lógico con dos operandos lógicos, parecido a or , pero no exactamente igual.
Evaluar e1 or else e2 supone evaluar e1 , y después
• si el resultado es true, la evaluación acaba con el valor true
• si el resultado es f alse, se evalúa e2 (obteniéndose el valor b), y la evaluación acaba con el valor b
Operadores no estrictos y estrictos
• and then y or else son no estrictos en su segundo operando, su implementación supone evaluación en
orden normal.
• and y or son ambos estrictos en sus dos operandos, su implementación supone orden ambicioso.
por tanto, and no es equivalente a and then , ni or es equivalente a or else
Ejemplo de ausencia de equivalencia.
A modo de ejemplo de la anterior afirmación, supongamos que b es un array de n valores lógicos, con índices
entre 0 y n − 1, e i es una variable que vale n:
• La evaluación de: (i < n and b[i ]) falla
• La evaluación de: (i < n and then b[i ]) produce f alse
23
6.1
Operadores o funciones no estrictas
6
ORDEN DE EVALUACIÓN
Subprogramas estrictos en lenguajes imperativos
• Cuando el orden de evaluación de las llamadas es ambicioso, no es posible declarar funciones no
estrictas en alguno de sus parámetros (los parámetros actuales se evalúan siempre).
• Este es el caso de los lenguajes imperativos más comunes.
Equivalencia de órdenes de evaluación:
Los tres órdenes difieren únicamente debido alguno de estos dos motivos:
• la presencia de efectos efectos laterales
• la evaluación de una expresión falla en orden ambicioso, pero no en orden normal o perezoso (aún
cuando no haya efectos laterales)
Equivalencia de órdenes de evaluación
La propiedad de Church-Roses.
En ausencia de efectos laterales, se cumple que:
• si una expresión se evalúa sin errores en algún orden, entonces se evalúa sin errores en orden normal
• si una expresión se evalúa sin errores en más de un orden de evaluación, entonces todos esos órdenes
de evaluación producen el mismo resultado.
fin del capítulo.
24
Descargar