En programación informática , un parámetro o argumento formal es un tipo especial de variable que se utiliza en una subrutina para hacer referencia a uno de los datos proporcionados como entrada a la subrutina. [a] [1] Estos datos son los valores [2] [3] [4] de los argumentos (a menudo llamados argumentos reales o parámetros reales ) con los que se llamará/invocará la subrutina. Por lo general, se incluye una lista ordenada de parámetros en la definición de una subrutina , de modo que, cada vez que se llama a la subrutina, se evalúan sus argumentos para esa llamada y los valores resultantes se pueden asignar a los parámetros correspondientes.
A diferencia del argumento en el uso matemático habitual, el argumento en informática es la expresión de entrada real que se pasa/suministra a una función, procedimiento o rutina en la declaración de invocación/llamada, mientras que el parámetro es la variable dentro de la implementación de la subrutina. Por ejemplo, si se define la add
subrutina como def add(x, y): return x + y
, entonces x, y
son los parámetros, mientras que si se llama a esta como add(2, 3)
, entonces 2, 3
son los argumentos. Las variables (y sus expresiones) del contexto de llamada pueden ser argumentos: si se llama a la subrutina como a = 2; b = 3; add(a, b)
entonces las variables a, b
son los argumentos, no los valores 2, 3
. Consulte la sección Parámetros y argumentos para obtener más información.
La semántica de cómo se pueden declarar los parámetros y cómo se pasan los (valores de) los argumentos a los parámetros de las subrutinas se define mediante la estrategia de evaluación del lenguaje, y los detalles de cómo se representa esto en cualquier sistema informático en particular dependen de la convención de llamada de ese sistema. En el caso más común, llamada por valor , un parámetro actúa dentro de la subrutina como una nueva variable local inicializada con el valor del argumento (una copia local (aislada) del argumento si el argumento es una variable), pero en otros casos, por ejemplo, llamada por referencia , la variable de argumento proporcionada por el llamador puede verse afectada por acciones dentro de la subrutina llamada.
El siguiente programa en lenguaje de programación C define una función denominada "SalesTax" y tiene un parámetro denominado "price". El tipo de precio es "double" (es decir, un número de punto flotante de doble precisión ). El tipo de retorno de la función también es doble.
double SalesTax ( doble precio ) { devolver 0,05 * precio ; }
Una vez definida la función, se puede invocar de la siguiente manera:
Impuesto sobre las ventas ( 10,00 );
En este ejemplo, la función se ha invocado con el argumento 10,00. Cuando esto sucede, se asignará 10,00 a price y la función comenzará a calcular su resultado. Los pasos para producir el resultado se especifican a continuación, entre {}. 0.05 * price
indica que lo primero que se debe hacer es multiplicar 0,05 por el valor de price, lo que da 0,50. return
significa que la función producirá el resultado de 0.05 * price
. Por lo tanto, el resultado final (ignorando los posibles errores de redondeo que se encuentran al representar fracciones decimales como fracciones binarias) es 0,50.
Los términos parámetro y argumento pueden tener significados diferentes en diferentes lenguajes de programación. A veces se usan indistintamente y se utiliza el contexto para distinguir el significado. El término parámetro (a veces llamado parámetro formal ) se usa a menudo para referirse a la variable tal como se encuentra en la declaración de función , mientras que argumento (a veces llamado parámetro real ) se refiere a la entrada real suministrada en la llamada de función. Por ejemplo, si uno define una función como def f(x): ...
, entonces x
es el parámetro, y si es llamada por a = ...; f(a)
entonces a
es el argumento. Un parámetro es una variable (no vinculada), mientras que el argumento puede ser un literal o variable o una expresión más compleja que involucra literales y variables. En el caso de la llamada por valor, lo que se pasa a la función es el valor del argumento - por ejemplo, f(2)
y a = 2; f(a)
son llamadas equivalentes - mientras que en la llamada por referencia, con una variable como argumento, lo que se pasa es una referencia a esa variable - aunque la sintaxis para la llamada de función podría permanecer igual. [5] La especificación para el paso por referencia o el paso por valor se haría en la declaración y/o definición de la función.
Los parámetros aparecen en las definiciones de procedimientos; los argumentos aparecen en las llamadas de procedimientos. En la definición de función , f(x) = x*x
la variable x es un parámetro; en la llamada de función, f(2)
el valor 2 es el argumento de la función. En términos generales, un parámetro es un tipo y un argumento es una instancia.
Un parámetro es una propiedad intrínseca del procedimiento, incluida en su definición. Por ejemplo, en muchos lenguajes, un procedimiento para sumar dos números enteros suministrados y calcular la suma necesitaría dos parámetros, uno para cada número entero. En general, un procedimiento puede definirse con cualquier número de parámetros o sin parámetros en absoluto. Si un procedimiento tiene parámetros, la parte de su definición que especifica los parámetros se denomina lista de parámetros .
Por el contrario, los argumentos son las expresiones [6] que se proporcionan al procedimiento cuando se lo llama, normalmente una expresión que coincide con uno de los parámetros. A diferencia de los parámetros, que forman una parte inmutable de la definición del procedimiento, los argumentos pueden variar de una llamada a otra. Cada vez que se llama a un procedimiento, la parte de la llamada al procedimiento que especifica los argumentos se denomina lista de argumentos .
Aunque los parámetros también se conocen comúnmente como argumentos, a veces se piensa que los argumentos son los valores reales o referencias asignadas a las variables de parámetro cuando se llama a la subrutina en tiempo de ejecución . Cuando se habla del código que llama a una subrutina, cualquier valor o referencia que se pase a la subrutina son los argumentos, y el lugar en el código donde se dan estos valores o referencias es la lista de parámetros . Cuando se habla del código dentro de la definición de la subrutina, las variables en la lista de parámetros de la subrutina son los parámetros, mientras que los valores de los parámetros en tiempo de ejecución son los argumentos. Por ejemplo, en C, cuando se trabaja con subprocesos es común pasar un argumento de tipo void* y convertirlo a un tipo esperado:
void ThreadFunction ( void * pThreadArgument ) { // Es correcto nombrar el primer parámetro 'pThreadArgument', en lugar de 'pThreadParameter'. En tiempo de ejecución, el valor que usamos es un argumento. Como se mencionó anteriormente, reserve el término parámetro para cuando se discutan las definiciones de subrutinas. }
Para comprender mejor la diferencia, considere la siguiente función escrita en C :
int Suma ( int suma1 , int suma2 ) { devolver suma1 + suma2 ; }
La función Sum tiene dos parámetros, denominados addend1 y addend2 . Suma los valores que se pasan a los parámetros y devuelve el resultado al llamador de la subrutina (utilizando una técnica proporcionada automáticamente por el compilador de C).
El código que llama a la función Suma podría verse así:
int valor1 = 40 ; int valor2 = 2 ; int suma_valor = Suma ( valor1 , valor2 );
Las variables valor1 y valor2 se inicializan con valores. Valor1 y valor2 son ambos argumentos de la función suma en este contexto.
En tiempo de ejecución, los valores asignados a estas variables se pasan a la función Sum como argumentos. En la función Sum , se evalúan los parámetros addend1 y addend2 , lo que genera los argumentos 40 y 2, respectivamente. Los valores de los argumentos se suman y el resultado se devuelve al llamador, donde se asigna a la variable sum_value .
Debido a la diferencia entre parámetros y argumentos, es posible que se proporcionen argumentos inadecuados a un procedimiento. La llamada puede proporcionar demasiados o muy pocos argumentos; uno o más de los argumentos pueden ser de un tipo incorrecto; o los argumentos pueden proporcionarse en el orden incorrecto. Cualquiera de estas situaciones provoca una falta de coincidencia entre las listas de parámetros y argumentos, y el procedimiento a menudo devolverá una respuesta no deseada o generará un error de tiempo de ejecución .
En el método y lenguaje de desarrollo de software Eiffel , los términos argumento y parámetro tienen usos distintos establecidos por convención. El término argumento se utiliza exclusivamente en referencia a las entradas de una rutina, [7] y el término parámetro se utiliza exclusivamente en la parametrización de tipos para clases genéricas . [8]
Considere la siguiente definición de rutina:
suma ( suma1 : ENTERO ; suma2 : ENTERO ): ENTERO hacer Resultado := suma1 + suma2 fin
La rutina sum
toma dos argumentos addend1
y addend2
, que se denominan argumentos formales de la rutina . Una llamada a sum
especifica los argumentos reales , como se muestra a continuación con value1
y value2
.
valor_suma : ENTERO valor1 : ENTERO = 40 valor2 : ENTERO = 2 … valor_suma := suma ( valor1 , valor2 )
Los parámetros también se consideran formales o reales . Los parámetros genéricos formales se utilizan en la definición de clases genéricas. En el ejemplo siguiente, la clase HASH_TABLE
se declara como una clase genérica que tiene dos parámetros genéricos formales, G
que representan datos de interés y K
representan la clave hash de los datos:
clase HASH_TABLE [ G , K -> HASHABLE ] …
Cuando una clase se convierte en cliente de HASH_TABLE
, los parámetros genéricos formales se sustituyen por parámetros genéricos reales en una derivación genérica . En la siguiente declaración de atributo, my_dictionary
se debe utilizar como un diccionario basado en cadenas de caracteres . Como tal, tanto los parámetros genéricos formales de datos como los de clave se sustituyen por parámetros genéricos reales de tipo STRING
.
mi_diccionario : TABLA_HASH [ CADENA , CADENA ]
En los lenguajes de programación fuertemente tipados , el tipo de cada parámetro debe especificarse en la declaración del procedimiento. Los lenguajes que utilizan inferencia de tipos intentan descubrir los tipos automáticamente a partir del cuerpo y el uso de la función. Los lenguajes de programación con tipado dinámico posponen la resolución de tipos hasta el tiempo de ejecución. Los lenguajes con tipado débil realizan poca o ninguna resolución de tipos y dependen en cambio del programador para la corrección.
Algunos lenguajes utilizan una palabra clave especial (por ejemplo, void ) para indicar que la subrutina no tiene parámetros; en la teoría de tipos formales , dichas funciones toman una lista de parámetros vacía (cuyo tipo no es void , sino unit ).
El mecanismo exacto para asignar argumentos a los parámetros, llamado paso de argumentos , depende de la estrategia de evaluación utilizada para ese parámetro (normalmente llamada por valor ), que puede especificarse mediante palabras clave.
Algunos lenguajes de programación como Ada , C++ , Clojure , [ cita requerida ] Common Lisp , [9] Fortran 90 , [10] Python , Ruby , Tcl y Windows PowerShell [ cita requerida ] permiten que se proporcione un argumento predeterminado de forma explícita o implícita en la declaración de una subrutina. Esto permite que el llamador omita ese argumento al llamar a la subrutina. Si el argumento predeterminado se proporciona explícitamente, se utiliza ese valor si el llamador no lo proporciona. Si el argumento predeterminado es implícito (a veces mediante el uso de una palabra clave como Option ), el lenguaje proporciona un valor conocido (como null , Empty , cero, una cadena vacía, etc.) si el llamador no proporciona un valor.
Ejemplo de PowerShell:
función doc ( $g = 1 . 21 ) { "$g gigavatios? $g gigavatios? ¡Genial Scott!" }
PS > doc ¿ 1,21 gigavatios? ¿1,21 gigavatios? ¡Genial Scott!PS > doc 88 ¿88 gigavatios? ¿88 gigavatios? ¡Genial Scott!
Los argumentos predeterminados pueden verse como un caso especial de la lista de argumentos de longitud variable.
Algunos lenguajes permiten definir subrutinas que acepten una cantidad variable de argumentos . En estos lenguajes, las subrutinas deben iterar a través de la lista de argumentos.
Ejemplo de PowerShell:
función marty { $args | foreach { "volver al año $_" } }
PS > marty 1985 volvemos al año 1985PS > marty 2015 1985 1955 de vuelta al año 2015 de vuelta al año 1985 de vuelta al año 1955
Algunos lenguajes de programación, como Ada y Windows PowerShell, permiten que las subrutinas tengan parámetros con nombre . Esto permite que el código de llamada sea más autodocumentado . También proporciona más flexibilidad al autor de la llamada, ya que a menudo permite cambiar el orden de los argumentos o que se omitan los argumentos según sea necesario.
Ejemplo de PowerShell:
función jennifer ( $adjetivoJoven , $adjetivoViejo ) { "Jennifer joven: ¡Soy $adjetivoJoven!" "Jennifer vieja: ¡Soy $adjetivoViejo!" }
PS > Jennifer "fresca" "experimentada" Jennifer joven: ¡Soy fresca! Jennifer vieja: ¡Soy experimentada!PS > jennifer -adjetivoVieja 'experimentada' -adjetivoJoven 'fresca' Jennifer joven: ¡Soy fresca! Jennifer vieja: ¡Soy experimentada!
En el cálculo lambda , cada función tiene exactamente un parámetro. Lo que se considera una función con múltiples parámetros se representa generalmente en el cálculo lambda como una función que toma el primer argumento y devuelve una función que toma el resto de los argumentos; esta es una transformación conocida como currying . Algunos lenguajes de programación, como ML y Haskell , siguen este esquema. En estos lenguajes, cada función tiene exactamente un parámetro, y lo que puede parecer la definición de una función de múltiples parámetros, es en realidad azúcar sintáctico para la definición de una función que devuelve una función, etc. La aplicación de funciones es asociativa por la izquierda en estos lenguajes, así como en el cálculo lambda, por lo que lo que parece una aplicación de una función a múltiples argumentos se evalúa correctamente como la función aplicada al primer argumento, luego la función resultante aplicada al segundo argumento, etc.
Un parámetro de salida , también conocido como parámetro de salida o parámetro de retorno , es un parámetro utilizado para la salida, en lugar del uso más habitual para la entrada. El uso de parámetros de llamada por referencia , o parámetros de llamada por valor donde el valor es una referencia, como parámetros de salida es una expresión idiomática en algunos lenguajes, en particular C y C++, [b] mientras que otros lenguajes tienen soporte integrado para parámetros de salida. Los lenguajes con soporte integrado para parámetros de salida incluyen Ada [11] (ver Subprogramas de Ada), Fortran (desde Fortran 90 ; ver Fortran "intent"), varias extensiones procedimentales para SQL , como PL/SQL (ver Funciones PL/SQL ) [12] y Transact-SQL , C# [13] y .NET Framework , [14] Swift , [15] y el lenguaje de scripting TScript (ver Declaraciones de funciones de TScript ).
Más precisamente, se pueden distinguir tres tipos de parámetros o modos de parámetros :parámetros de entrada ,parámetros de salidayparámetros de entrada/salida ;estos a menudo se denotan comoin
,out
yin out
oinout
. Un argumento de entrada (el argumento de un parámetro de entrada) debe ser un valor, como una variable inicializada o literal, y no debe redefinirse ni asignarse a él; un argumento de salida debe ser una variable asignable, pero no necesita inicializarse, ningún valor existente es accesible y se le debe asignar un valor; y un argumento de entrada/salida debe ser una variable inicializada y asignable, y opcionalmente se le puede asignar un valor. Los requisitos exactos y su aplicación varían entre lenguajes; por ejemplo, enAda 83los parámetros de salida solo se pueden asignar, no leer, incluso después de la asignación (esto se eliminó enAda 95para eliminar la necesidad de una variable acumuladora auxiliar). Estos son análogos a la noción de unvaloren una expresión que es un valor r (tiene un valor), un valor l (se puede asignar) o un valor r/valor l (tiene un valor y se puede asignar), respectivamente, aunque estos términos tienen significados especializados en C.
En algunos casos, solo se distinguen la entrada y la entrada/salida, y la salida se considera un uso específico de la entrada/salida, y en otros casos solo se admiten la entrada y la salida (pero no la entrada/salida). El modo predeterminado varía entre lenguajes: en Fortran 90, la entrada/salida es predeterminada, mientras que en C# y las extensiones SQL, la entrada es predeterminada, y en TScript cada parámetro se especifica explícitamente como entrada o salida.
Sintácticamente, el modo de parámetro se indica generalmente con una palabra clave en la declaración de la función, como void f(out int x)
en C#. Convencionalmente, los parámetros de salida se suelen colocar al final de la lista de parámetros para distinguirlos claramente, aunque esto no siempre se sigue. TScript utiliza un enfoque diferente, donde en la declaración de la función se enumeran los parámetros de entrada y luego los parámetros de salida, separados por dos puntos (:) y no hay ningún tipo de retorno para la función en sí, como en esta función, que calcula el tamaño de un fragmento de texto:
TextExtent ( WString text , Font font : ancho entero , alto entero )
Los modos de parámetros son una forma de semántica denotacional , que establece la intención del programador y permite a los compiladores detectar errores y aplicar optimizaciones; no implican necesariamente semántica operacional (cómo ocurre realmente el paso de parámetros). En particular, si bien los parámetros de entrada se pueden implementar mediante una llamada por valor, y los parámetros de salida y de entrada/salida mediante una llamada por referencia (y esta es una forma sencilla de implementar estos modos en lenguajes sin soporte integrado), no siempre es así como se implementan. Esta distinción se analiza en detalle en el Fundamento de Ada '83, que enfatiza que el modo de parámetro se abstrae de qué mecanismo de paso de parámetros (por referencia o por copia) se implementa realmente. [11] Por ejemplo, mientras que en C# los parámetros de entrada (predeterminado, sin palabra clave) se pasan por valor, y los parámetros de salida y de entrada/salida ( out
y ref
) se pasan por referencia, en PL/SQL los parámetros de entrada ( IN
) se pasan por referencia, y los parámetros de salida y de entrada/salida ( OUT
y IN OUT
) se pasan por valor de forma predeterminada y el resultado se copia de nuevo, pero se pueden pasar por referencia utilizando la NOCOPY
sugerencia del compilador. [16]
Una construcción sintácticamente similar a los parámetros de salida es asignar el valor de retorno a una variable con el mismo nombre que la función. Esto se encuentra en Pascal y Fortran 66 y Fortran 77 , como en este ejemplo de Pascal:
función f ( x , y : entero ) : entero ; inicio f := x + y ; fin ;
Esto es semánticamente diferente en el sentido de que cuando se llama, la función simplemente se evalúa; no se le pasa una variable desde el ámbito de llamada para almacenar la salida.
El uso principal de los parámetros de salida es devolver múltiples valores de una función, mientras que el uso de los parámetros de entrada/salida es modificar el estado mediante el paso de parámetros (en lugar de mediante un entorno compartido, como en las variables globales). Un uso importante de la devolución de múltiples valores es resolver el problema de semipredicado de devolver tanto un valor como un estado de error; consulte Problema de semipredicado: retorno multivalor .
Por ejemplo, para devolver dos variables de una función en C, se puede escribir:
int ancho int alto ; F ( x , & ancho , & alto );
donde x
es un parámetro de entrada y width
son height
parámetros de salida.
Un caso de uso común en C y lenguajes relacionados es el manejo de excepciones , donde una función coloca el valor de retorno en una variable de salida y devuelve un valor booleano que indica si la función tuvo éxito o no. Un ejemplo arquetípico es el TryParse
método en .NET, especialmente C#, que analiza una cadena en un entero y devuelve true
el resultado en caso de éxito y false
de error. Este método tiene la siguiente firma: [17]
público estático bool TryParse ( cadena s , salida int resultado )
y puede utilizarse de la siguiente manera:
int resultado ; if ( ! Int32 . TryParse ( s , resultado )) { // manejo de excepciones }
Se aplican consideraciones similares al retorno de un valor de uno de varios tipos posibles, donde el valor de retorno puede especificar el tipo y luego el valor se almacena en una de varias variables de salida.
Los parámetros de salida suelen desaconsejarse en la programación moderna, básicamente por ser incómodos, confusos y de nivel demasiado bajo; los valores de retorno comunes son considerablemente más fáciles de entender y trabajar con ellos. [18] En particular, los parámetros de salida involucran funciones con efectos secundarios (que modifican el parámetro de salida) y son semánticamente similares a las referencias, que son más confusas que las funciones y los valores puros, y la distinción entre parámetros de salida y parámetros de entrada/salida puede ser sutil. Además, dado que en los estilos de programación comunes la mayoría de los parámetros son simplemente parámetros de entrada, los parámetros de salida y los parámetros de entrada/salida son inusuales y, por lo tanto, susceptibles de malentendidos.
Los parámetros de salida y de entrada/salida impiden la composición de funciones , ya que la salida se almacena en variables, en lugar de en el valor de una expresión. Por lo tanto, primero se debe declarar una variable y luego cada paso de una cadena de funciones debe ser una declaración separada. Por ejemplo, en C++ la siguiente composición de funciones:
Objeto obj = G ( y , F ( x ));
cuando se escribe con parámetros de salida y de entrada/salida se convierte en (ya que F
es un parámetro de salida, para G
un parámetro de entrada/salida):
Objeto obj ; F ( x , & obj ); G ( y , & obj );
En el caso especial de una función con un solo parámetro de salida o entrada/salida y sin valor de retorno, la composición de la función es posible si el parámetro de salida o entrada/salida (o en C/C++, su dirección) también es devuelto por la función, en cuyo caso lo anterior se convierte en:
Objeto obj ; G ( y , F ( x , & obj ));
Existen varias alternativas a los casos de uso de los parámetros de salida.
Para devolver varios valores de una función, una alternativa es devolver una tupla . Sintácticamente, esto es más claro si se puede utilizar la descompresión de secuencia automática y la asignación paralela , como en Go o Python, por ejemplo:
def f (): devuelve 1 , 2 a , b = f ()
Para devolver un valor de uno de varios tipos, se puede utilizar una unión etiquetada ; los casos más comunes son los tipos que aceptan valores nulos ( tipos de opción ), donde el valor de retorno puede ser nulo para indicar un error. Para el manejo de excepciones, se puede devolver un tipo que acepta valores nulos o generar una excepción. Por ejemplo, en Python se podría tener:
resultado = analizar ( s ) si el resultado es Ninguno : # manejo de excepciones
o, más idiomáticamente:
try : result = parse ( s ) except ParseError : # manejo de excepciones
La microoptimización de no requerir una variable local y copiar el retorno cuando se utilizan variables de salida también se puede aplicar a funciones convencionales y valores de retorno mediante compiladores suficientemente sofisticados.
La alternativa habitual a los parámetros de salida en C y lenguajes relacionados es devolver una única estructura de datos que contenga todos los valores de retorno. [13] Por ejemplo, dada una estructura que encapsule el ancho y la altura, se puede escribir:
AnchoAlto ancho_y_alto = F ( x );
En los lenguajes orientados a objetos, en lugar de utilizar parámetros de entrada/salida, a menudo se puede usar call compartiendo , pasando una referencia a un objeto y luego mutando el objeto, aunque sin cambiar a qué objeto se refiere la variable. [18]
Los parámetros hacen referencia a la lista de variables en una declaración de método. Los argumentos son los valores reales que se pasan cuando se invoca el método. Cuando se invoca un método, los argumentos utilizados deben coincidir con los parámetros de la declaración en tipo y orden.