En programación de computadoras , un parámetro o argumento formal es un tipo especial de variable que se utiliza en una subrutina para referirse 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. Generalmente 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 pasada/suministrada 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 uno define la add
subrutina como def add(x, y): return x + y
, entonces x, y
son los parámetros, mientras que si se llama como add(2, 3)
, entonces 2, 3
son los argumentos. Las variables (y sus expresiones) del contexto de llamada pueden ser argumentos: si la subrutina se llama 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 (el valor de) los argumentos a los parámetros de las subrutinas está definida por 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 llamada. convención 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 la persona que llama puede verse afectada por acciones dentro de la subrutina llamada.
El siguiente programa en el lenguaje de programación C define una función que se denomina "SalesTax" y tiene un parámetro llamado "precio". El tipo de precio es "doble" (es decir, un número de coma flotante de doble precisión ). El tipo de retorno de la función también es doble.
doble Impuesto sobre las Ventas ( precio doble ) { retorno 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 invocó con el argumento 10.00. Cuando esto suceda, se asignará 10,00 al precio 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 hay que hacer es multiplicar 0,05 por el valor del precio, 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 diferentes significados en diferentes lenguajes de programación. A veces se usan indistintamente y el contexto se usa 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 definición de la función, mientras que argumento (a veces llamado parámetro real ) se refiere a la entrada real proporcionada en la llamada a la función. Por ejemplo, si uno define una función como def f(x): ...
, entonces x
es el parámetro, y si se llama a = ...; f(a)
entonces a
es el argumento. Un parámetro es una variable (independiente), mientras que el argumento puede ser un literal o una variable o una expresión más compleja que incluya 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 de la llamada a la función podría seguir siendo la misma. [5] La especificación de paso por referencia o 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 a procedimientos. En la definición de la función f(x) = x*x
la variable x es un parámetro; en la llamada a 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 idiomas, un procedimiento para sumar dos números enteros proporcionados 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 ningún parámetro. Si un procedimiento tiene parámetros, la parte de su definición que especifica los parámetros se llama lista de parámetros .
Por el contrario, los argumentos son las expresiones [6] proporcionadas al procedimiento cuando se 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 denominan comúnmente argumentos, a veces se piensa que los argumentos son los valores reales o referencias asignadas a las variables de parámetros cuando se llama a la subrutina en tiempo de ejecución . Cuando se analiza el código que llama a una subrutina, cualquier valor o referencia pasada 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 analiza el código dentro de la definición de 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 trata de subprocesos, es común pasar un argumento de tipo void* y convertirlo a un tipo esperado:
void ThreadFunction ( void * pThreadArgument ) { // Nombrar el primer parámetro 'pThreadArgument' es correcto, en lugar de // 'pThreadParameter'. En tiempo de ejecución el valor que utilizamos es un argumento. Como // se mencionó anteriormente, reserve el término parámetro para cuando // analice las definiciones de subrutinas. }
Para comprender mejor la diferencia, considere la siguiente función escrita en C :
int suma ( int sumando1 , int sumando2 ) { return sumando1 + sumando2 ; }
La función Suma tiene dos parámetros, denominados sumando1 y sumando2 . Agrega los valores pasados 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í:
valor int1 = 40 ; valor int2 = 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 de suma en este contexto.
En tiempo de ejecución, los valores asignados a estas variables se pasan a la función Suma como argumentos. En la función Suma , se evalúan los parámetros sumando1 y sumando2 , lo que produce los argumentos 40 y 2, respectivamente. Los valores de los argumentos se suman y el resultado se devuelve a la persona que llama, donde se asigna a la variable sum_value .
Debido a la diferencia entre parámetros y argumentos, es posible proporcionar argumentos inadecuados a un procedimiento. La convocatoria puede aportar 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 .
Dentro del método y lenguaje de desarrollo de software de Eiffel , los términos argumento y parámetro tienen usos distintos establecidos por convención. El término argumento se usa exclusivamente en referencia a las entradas de una rutina, [7] y el término parámetro se usa exclusivamente en la parametrización de tipos para clases genéricas . [8]
Considere la siguiente definición de rutina:
suma ( sumado1 : INTEGER ; addend2 : INTEGER ): INTEGER do Resultado := addend1 + addend2 end
La rutina sum
toma dos argumentos addend1
y addend2
, que se denominan argumentos formales de la rutina . Una llamada a sum
especifica argumentos reales , como se muestra a continuación con value1
y value2
.
valor_suma : INTEGER valor1 : INTEGER = 40 valor2 : INTEGER = 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 siguiente ejemplo, 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 atributos, my_dictionary
se utilizará como un diccionario basado en cadenas de caracteres . Como tal, tanto los datos como los parámetros genéricos formales clave se sustituyen por parámetros genéricos reales de tipo STRING
.
mi_diccionario : HASH_TABLE [ STRING , STRING ]
En lenguajes de programación fuertemente tipados , el tipo de cada parámetro debe especificarse en la declaración del procedimiento. Los lenguajes que utilizan la 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 tipados dinámicamente difieren la resolución de tipos hasta el tiempo de ejecución. Los lenguajes débilmente tipados realizan poca o ninguna resolución de tipos, confiando en cambio en el programador para su corrección.
Algunos lenguajes usan una palabra clave especial (por ejemplo, void ) para indicar que la subrutina no tiene parámetros; En la teoría de tipos formal , tales funciones toman una lista de parámetros vacía (cuyo tipo no es void , sino unit ).
El mecanismo exacto para asignar argumentos a 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 un argumento predeterminado sea explícito o implícito. dado en la declaración de una subrutina. Esto permite a la persona que llama omitir ese argumento al llamar a la subrutina. Si el argumento predeterminado se proporciona explícitamente, entonces ese valor se utiliza si no lo proporciona la persona que llama. Si el argumento predeterminado es implícito (a veces mediante el uso de una palabra clave como Opcional ), entonces el lenguaje proporciona un valor conocido (como nulo , Vacío , cero, una cadena vacía, etc.) si la persona que llama no proporciona un valor. .
Ejemplo de PowerShell:
function doc ( $g = 1 . 21 ) { "¿$g gigavatios? $g gigavatios? ¡Excelente Scott!" }
PD > doc 1,21 gigavatios? ¿1,21 gigavatios? ¡Gran Scott!PD > doc 88 88 gigavatios? ¿88 gigavatios? ¡Gran Scott!
Los argumentos predeterminados pueden verse como un caso especial de la lista de argumentos de longitud variable.
Algunos lenguajes permiten definir subrutinas para aceptar un número variable de argumentos . Para dichos lenguajes, las subrutinas deben recorrer la lista de argumentos.
Ejemplo de PowerShell:
función marty { $args | foreach { "volver al año $_" } }
PD > marty 1985 volviendo al año 1985PD > marty 2015 1985 1955 volver al año 2015 volver al año 1985 volver 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 a la persona que llama, ya que a menudo permite cambiar el orden de los argumentos o omitirlos según sea necesario.
Ejemplo de PowerShell:
function jennifer ( $adjectiveYoung , $adjectiveOld ) { "Joven Jennifer: ¡Soy $adjectiveYoung!" "Vieja Jennifer: ¡Soy $adjetivoOld!" }
PD > jennifer 'fresca' 'experimentada' Joven Jennifer: ¡Estoy fresca! Vieja Jennifer: ¡Tengo experiencia!PD > jennifer -adjetivoVieja 'experimentada' -adjetivoJoven 'fresca' Joven Jennifer: ¡Estoy fresca! Vieja Jennifer: ¡Tengo experiencia!
En el cálculo lambda , cada función tiene exactamente un parámetro. Lo que se considera funciones con múltiples parámetros generalmente se representa 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 curry . 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, en realidad es 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 izquierda en estos lenguajes así como en 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 que se utiliza para la salida, en lugar del uso más habitual para la entrada. Usar 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 un modismo en algunos lenguajes, especialmente 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] (consulte Subprogramas de Ada), Fortran (desde Fortran 90 ; consulte "intención" de Fortran), varias extensiones de procedimientos para SQL , como PL/SQL (consulte Funciones PL/SQL ) [12] y Transact-SQL , C# [13] y .NET Framework , [14] Swift , [15] y el lenguaje de secuencias de comandos TScript (consulte 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ámetrosde salidayparámetros de entrada/salida ;estos a menudo se denotanin
,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 un literal, y no se debe redefinir ni asignar; un argumento de salida debe ser una variable asignable, pero no es necesario inicializarlo, no se puede acceder a ningún valor existente 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 la aplicación varían según el idioma; 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 que unvaloren una expresión 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, considerándose la salida 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 idiomas: en Fortran 90 la entrada/salida es la predeterminada, mientras que en C# y las extensiones SQL la entrada es la predeterminada, y en TScript cada parámetro se especifica explícitamente como entrada o salida.
Sintácticamente, el modo de parámetro generalmente se indica con una palabra clave en la declaración de función, como void f(out int x)
en C#. Convencionalmente, los parámetros de salida suelen colocarse al final de la lista de parámetros para distinguirlos claramente, aunque esto no siempre se cumple. TScript utiliza un enfoque diferente, donde en la declaración de función se enumeran los parámetros de entrada, 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 texto. fragmento:
TextExtent ( texto WString , fuente de fuente : 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 una semántica operativa (cómo ocurre realmente el paso de parámetros). En particular, si bien los parámetros de entrada se pueden implementar mediante llamada por valor, y los parámetros de salida y de entrada/salida mediante llamada por referencia (y esta es una forma sencilla de implementar estos modos en lenguajes sin soporte integrado), no siempre es así. implementado. Esta distinción se analiza en detalle en el fundamento de Ada '83, que enfatiza que el modo de parámetro se abstrae del mecanismo de paso de parámetro (por referencia o por copia) que realmente se implementa. [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 entrada/salida ( OUT
y IN OUT
) se pasan de forma predeterminada por valor 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 ; comenzar f := x + y ; fin ;
Esto es semánticamente diferente en que cuando se llama, la función simplemente se evalúa: no se le pasa una variable desde el alcance de la 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 devolver múltiples valores es resolver el problema de semipredicado de devolver tanto un valor como un estado de error; consulte Problema de semipredicado: devolución con múltiples valores .
Por ejemplo, para devolver dos variables de una función en C, se puede escribir:
ancho int alto ; F ( x , ancho y alto ) ;
donde x
es un parámetro de entrada y width
y height
son 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 booleano correspondiente a 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 número entero y regresa true
en caso de éxito o false
de error. Este tiene la siguiente firma: [17]
bool estático público TryParse ( cadena s , resultado int )
y se puede utilizar de la siguiente manera:
resultado entero ; if ( ! Int32 . TryParse ( s , resultado )) { // manejo de excepciones }
Se aplican consideraciones similares a la devolución de un valor de uno de varios tipos posibles, donde el valor devuelto puede especificar el tipo y luego el valor se almacena en una de varias variables de salida.
Los parámetros de salida a menudo no se recomiendan en la programación moderna, esencialmente 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 (modificar el parámetro de salida) y son semánticamente similares a las referencias, que son más confusas que las funciones y 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 tanto, susceptibles de malentendidos.
Los parámetros de salida y 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, inicialmente 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 entrada/salida se convierte en (porque F
es un parámetro de salida, para G
un parámetro de entrada/salida):
Objeto objeto ; F ( x , & obj ); G ( y , & obj );
En el caso especial de una función con un único parámetro de salida o entrada/salida y sin valor de retorno, la composición de la función es posible si la función también devuelve el parámetro de salida o entrada/salida (o en C/C++, su dirección). en cuyo caso lo anterior pasa a ser:
Objeto objeto ; G ( y , F ( x , & obj ));
Existen varias alternativas a los casos de uso de parámetros de salida.
Para devolver múltiples valores de una función, una alternativa es devolver una tupla . Sintácticamente esto es más claro si se puede usar el desempaquetado automático de secuencias y la asignación paralela , como en Go o Python, como 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 NULL ( tipos de opciones ), 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 NULL 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:
intentar : resultado = analizar ( s ) excepto ParseError : # manejo de excepciones
La microoptimización de no requerir una variable local y copiar el retorno cuando se usan 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 devueltos. [13] Por ejemplo, dada una estructura que encapsula ancho y alto, se puede escribir:
AnchoAlto ancho_y_alto = F ( x );
En los lenguajes orientados a objetos, en lugar de usar parámetros de entrada/salida, a menudo se puede usar call by share , 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 se refieren 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 invoca un método, los argumentos utilizados deben coincidir con los parámetros de la declaración en tipo y orden.