Recent from talks
Nothing was collected or created yet.
Parameter (computer programming)
View on WikipediaIn computer programming, a parameter, a.k.a. formal argument, is a variable that represents an argument, a.k.a. actual argument, a.k.a. actual parameter, to a function call.[1][2][3][4] A function's signature defines its parameters. A call invocation involves evaluating each argument expression of a call and associating the result with the corresponding parameter.
For example, consider the Python function
def add(x: int, y: int) -> int:
return x + y
Variables x and y are parameters, each of type int. For call add(2, 3), the expressions 2 and 3 are arguments. For call add(a+1, b+2), the arguments are a+1 and b+2.
Parameter passing is defined by a programming language. Evaluation strategy defines the semantics for how parameters can be declared and how arguments are passed to a function. Generally, with call by value, a parameter acts like a new, local variable initialized to the value of the argument. If the argument is a variable, the function cannot modify the argument state because the parameter is a copy. With call by reference, which requires the argument to be a variable, the parameter is an alias of the argument.
Example
[edit]The following C source code defines a function named salesTax with one parameter named price; both typed double. For call salesTax(10.00), the argument 10.00 is passed to the function as the double value 10 and assigned to parameter variable price, and the function returns 0.5.
double salesTax(double price) {
return 0.05 * price;
}
Parameters and arguments
[edit]The terms parameter and argument may have different meanings in different programming languages. Sometimes they are used interchangeably, and the context is used to distinguish the meaning. The term parameter (sometimes called formal parameter) is often used to refer to the variable as found in the function declaration, while argument (sometimes called actual parameter) refers to the actual input supplied at a function call statement. For example, if one defines a function as def f(x): ..., then x is the parameter, and if it is called by a = ...; f(a) then a is the argument. A parameter is an (unbound) variable, while the argument can be a literal or variable or more complex expression involving literals and variables. In case of call by value, what is passed to the function is the value of the argument – for example, f(2) and a = 2; f(a) are equivalent calls – while in call by reference, with a variable as argument, what is passed is a reference to that variable - even though the syntax for the function call could stay the same.[5] The specification for pass-by-reference or pass-by-value would be made in the function declaration and/or definition.
Parameters appear in procedure definitions; arguments appear in procedure calls. In the function definition f(x) = x*x the variable x is a parameter; in the function call f(2) the value 2 is the argument of the function. Loosely, a parameter is a type, and an argument is an instance.
A parameter is an intrinsic property of the procedure, included in its definition. For example, in many languages, a procedure to add two supplied integers together and calculate the sum would need two parameters, one for each integer. In general, a procedure may be defined with any number of parameters, or no parameters at all. If a procedure has parameters, the part of its definition that specifies the parameters is called its parameter list.
By contrast, the arguments are the expressions[6] supplied to the procedure when it is called, usually one expression matching one of the parameters. Unlike the parameters, which form an unchanging part of the procedure's definition, the arguments may vary from call to call. Each time a procedure is called, the part of the procedure call that specifies the arguments is called the argument list.
Although parameters are also commonly referred to as arguments, arguments are sometimes thought of as the actual values or references assigned to the parameter variables when the function is called at run-time. When discussing code that is calling into a function, any values or references passed into the function are the arguments, and the place in the code where these values or references are given is the parameter list. When discussing the code inside the function definition, the variables in the function's parameter list are the parameters, while the values of the parameters at runtime are the arguments.
Consider the following C function, sum, which has two parameters, addend1 and addend2. It adds the values passed into the parameters, and returns the result to the function's caller.
int sum(int addend1, int addend2) {
return addend1 + addend2;
}
The following is an example of calling sum. The variables value1 and value2 are initialized and then passed to Sum as the arguments. At runtime, the values assigned to these variables are passed to sum. In sum, the parameters addend1 and addend2 are evaluated, yielding the arguments 40 and 2, respectively. The values of the arguments are added, and the result is returned to the caller, where it is assigned to the variable sum_value.
int value1 = 40;
int value2 = 2;
int sum_value = sum(value1, value2);
Because of the difference between parameters and arguments, it is possible to supply inappropriate arguments to a procedure. The call may supply too many or too few arguments; one or more of the arguments may be a wrong type; or arguments may be supplied in the wrong order. Any of these situations causes a mismatch between the parameter and argument lists, and the procedure will often return an unintended answer or generate a runtime error.
Alternative convention in Eiffel
[edit]Within the Eiffel software development method and language, the terms argument and parameter have distinct uses established by convention. The term argument is used exclusively in reference to a routine's inputs,[7] and the term parameter is used exclusively in type parameterization for generic classes.[8]
Consider the following routine definition:
sum (addend1: INTEGER; addend2: INTEGER): INTEGER
do
Result := addend1 + addend2
end
The routine sum takes two arguments addend1 and addend2, which are called the routine's formal arguments. A call to sum specifies actual arguments, as shown below with value1 and value2.
sum_value: INTEGER
value1: INTEGER = 40
value2: INTEGER = 2
…
sum_value := sum (value1, value2)
Parameters are also thought of as either formal or actual. Formal generic parameters are used in the definition of generic classes. In the example below, the class HASH_TABLE is declared as a generic class which has two formal generic parameters, G representing data of interest and K representing the hash key for the data:
class HASH_TABLE [G, K -> HASHABLE]
…
When a class becomes a client to HASH_TABLE, the formal generic parameters are substituted with actual generic parameters in a generic derivation. In the following attribute declaration, my_dictionary is to be used as a character string based dictionary. As such, both data and key formal generic parameters are substituted with actual generic parameters of type STRING.
my_dictionary: HASH_TABLE [STRING, STRING]
Datatypes
[edit]In strongly typed programming languages, each parameter's type must be specified in the procedure declaration. Languages using type inference attempt to discover the types automatically from the function's body and usage. Dynamically typed programming languages defer type resolution until run-time. Weakly typed languages perform little to no type resolution, relying instead on the programmer for correctness.
Some languages use a special keyword (e.g. void) to indicate that the function has no parameters; in formal type theory, such functions take an empty parameter list (whose type is not void, but rather unit).
Argument passing
[edit]The mechanism for assigning arguments to parameters, called argument passing, depends upon the evaluation strategy used for that parameter (typically call by value), which may be specified using keywords.
Default arguments
[edit]Some programming languages such as Ada, C++, Clojure,[citation needed] Common Lisp,[9] Fortran 90,[10] Python, Ruby, Tcl, and Windows PowerShell[citation needed] allow for a default argument to be explicitly or implicitly given in a function's declaration. This allows the caller to omit that argument when calling the function. If the default argument is explicitly given, then that value is used if it is not provided by the caller. If the default argument is implicit (sometimes by using a keyword such as Optional) then the language provides a well-known value (such as null, Empty, zero, an empty string, etc.) if a value is not provided by the caller.
PowerShell example:
function doc($g = 1.21) {
"$g gigawatts? $g gigawatts? Great Scott!"
}
PS > doc
1.21 gigawatts? 1.21 gigawatts? Great Scott!
PS > doc 88
88 gigawatts? 88 gigawatts? Great Scott!
Default arguments can be seen as a special case of the variable-length argument list.
Variable-length parameter lists
[edit]Some languages allow functions to be defined to accept a variable number of arguments. For such languages, the functions must iterate through the list of arguments.
PowerShell example:
function marty {
$args | foreach { "back to the year $_" }
}
PS > marty 1985
back to the year 1985
PS > marty 2015 1985 1955
back to the year 2015
back to the year 1985
back to the year 1955
Named parameters
[edit]Some programming languages—such as Ada and Windows PowerShell—allow functions to have named parameters. This allows the calling code to be more self-documenting. It also provides more flexibility to the caller, often allowing the order of the arguments to be changed, or for arguments to be omitted as needed.
PowerShell example:
function jennifer($adjectiveYoung, $adjectiveOld) {
"Young Jennifer: I'm $adjectiveYoung!"
"Old Jennifer: I'm $adjectiveOld!"
}
PS > jennifer 'fresh' 'experienced'
Young Jennifer: I'm fresh!
Old Jennifer: I'm experienced!
PS > jennifer -adjectiveOld 'experienced' -adjectiveYoung 'fresh'
Young Jennifer: I'm fresh!
Old Jennifer: I'm experienced!
Multiple parameters in functional languages
[edit]In lambda calculus, each function has exactly one parameter. What is thought of as functions with multiple parameters is usually represented in lambda calculus as a function which takes the first argument, and returns a function which takes the rest of the arguments; this is a transformation known as currying. Some programming languages, like ML and Haskell, follow this scheme. In these languages, every function has exactly one parameter, and what may look like the definition of a function of multiple parameters, is actually syntactic sugar for the definition of a function that returns a function, etc. Function application is left-associative in these languages as well as in lambda calculus, so what looks like an application of a function to multiple arguments is correctly evaluated as the function applied to the first argument, then the resulting function applied to the second argument, etc.
Output parameters
[edit]An output parameter, also known as an out parameter or return parameter, is a parameter used for output, rather than the more usual use for input. Using call by reference parameters, or call by value parameters where the value is a reference, as output parameters is an idiom in some languages, notably C and C++,[a] while other languages have built-in support for output parameters. Languages with built-in support for output parameters include Ada[11] (see Ada subprograms), Fortran (since Fortran 90; see Fortran "intent"), various procedural extensions to SQL, such as PL/SQL (see PL/SQL functions)[12] and Transact-SQL, C#[13] and the .NET Framework,[14] Swift,[15] and the scripting language TScript (see TScript function declarations).
Here is an example of an "output parameter" in C:
//definition of a function with an output parameter
void f(int x, int y, int *out) {
*out = x + y;
}
//usage
int foo = 1;
int bar = 2;
int baz;
f(foo, bar, &baz);
The function will return nothing, but the value of x + y will be assigned to the variable whose address is passed in as out.
More precisely, one may distinguish three types of parameters or parameter modes: input parameters, output parameters, and input/output parameters; these are often denoted in, out, and in out or inout. An input argument (the argument to an input parameter) must be a value, such as an initialized variable or literal, and must not be redefined or assigned to; an output argument must be an assignable variable, but it need not be initialized, any existing value is not accessible, and must be assigned a value; and an input/output argument must be an initialized, assignable variable, and can optionally be assigned a value. The exact requirements and enforcement vary between languages – for example, in Ada 83 output parameters can only be assigned to, not read, even after assignment (this was removed in Ada 95 to remove the need for an auxiliary accumulator variable). These are analogous to the notion of a value in an expression being an r-value (has a value), an l-value (can be assigned), or an r-value/l-value (has a value and can be assigned), respectively, though these terms have specialized meanings in C.
In some cases only input and input/output are distinguished, with output being considered a specific use of input/output, and in other cases only input and output (but not input/output) are supported. The default mode varies between languages: in Fortran 90 input/output is default, while in C# and SQL extensions input is default, and in TScript each parameter is explicitly specified as input or output.
Syntactically, parameter mode is generally indicated with a keyword in the function declaration, such as void f(out int x) in C#. Conventionally output parameters are often put at the end of the parameter list to clearly distinguish them, though this is not always followed. TScript uses a different approach, where in the function declaration input parameters are listed, then output parameters, separated by a colon (:) and there is no return type to the function itself, as in this function, which computes the size of a text fragment:
TextExtent(WString text, Font font : Integer width, Integer height)
Parameter modes are a form of denotational semantics, stating the programmer's intent and allowing compilers to catch errors and apply optimizations – they do not necessarily imply operational semantics (how the parameter passing actually occurs). Notably, while input parameters can be implemented by call by value, and output and input/output parameters by call by reference – and this is a straightforward way to implement these modes in languages without built-in support – this is not always how they are implemented. This distinction is discussed in detail in the Ada '83 Rationale, which emphasizes that the parameter mode is abstracted from which parameter passing mechanism (by reference or by copy) is actually implemented.[11] For instance, while in C# input parameters (default, no keyword) are passed by value, and output and input/output parameters (out and ref) are passed by reference, in PL/SQL input parameters (IN) are passed by reference, and output and input/output parameters (OUT and IN OUT) are by default passed by value and the result copied back, but can be passed by reference by using the NOCOPY compiler hint.[16]
A syntactically similar construction to output parameters is to assign the return value to a variable with the same name as the function. This is found in Pascal and Fortran 66 and Fortran 77, as in this Pascal example:
function f(x, y: integer): integer;
begin
f := x + y;
end;
This is semantically different in that when called, the function is simply evaluated – it is not passed a variable from the calling scope to store the output in.
Use
[edit]The primary use of output parameters is to return multiple values from a function, while the use of input/output parameters is to modify state using parameter passing (rather than by shared environment, as in global variables). An important use of returning multiple values is to solve the semipredicate problem of returning both a value and an error status – see Semipredicate problem: Multivalued return.
For example, to return two variables from a function in C, one may write:
int width
int height;
f(x, &width, &height);
where x is an input parameter and width and height are output parameters.
A common use case in C and related languages is for exception handling, where a function places the return value in an output variable, and returns a Boolean corresponding to whether the function succeeded or not. An archetypal example is the TryParse method in .NET, especially C#, which parses a string into an integer, returning true on success and false on failure. This has the following signature:[17]
public static bool TryParse(string s, out int result)
and may be used as follows:
int result;
if (!Int32.TryParse(s, result)) {
// exception handling
}
Similar considerations apply to returning a value of one of several possible types, where the return value can specify the type and then value is stored in one of several output variables.
Drawbacks
[edit]Output parameters are often discouraged in modern programming, essentially as being awkward, confusing, and too low-level – commonplace return values are considerably easier to understand and work with.[18] Notably, output parameters involve functions with side effects (modifying the output parameter) and are semantically similar to references, which are more confusing than pure functions and values, and the distinction between output parameters and input/output parameters can be subtle. Further, since in common programming styles most parameters are simply input parameters, output parameters and input/output parameters are unusual and hence susceptible to misunderstanding.
Output and input/output parameters prevent function composition, since the output is stored in variables, rather than in the value of an expression. Thus one must initially declare a variable, and then each step of a chain of functions must be a separate statement. For example, in C++ the following function composition:
MyObject obj = g(y, f(x));
when written with output and input/output parameters instead becomes (for F it is an output parameter, for G an input/output parameter):
MyObject obj;
f(x, &obj);
g(y, &obj);
In the special case of a function with a single output or input/output parameter and no return value, function composition is possible if the output or input/output parameter (or in C/C++, its address) is also returned by the function, in which case the above becomes:
MyObject obj;
g(y, f(x, &obj));
Alternatives
[edit]There are various alternatives to the use cases of output parameters.
For returning multiple values from a function, an alternative is to return a tuple. Syntactically this is clearer if automatic sequence unpacking and parallel assignment can be used, as in Go or Python, such as:
def f() -> Tuple[int, int]:
return 1, 2
a, b = f()
For returning a value of one of several types, a tagged union can be used instead; the most common cases are nullable types (option types), where the return value can be null to indicate failure. For exception handling, one can return a nullable type, or raise an exception. For example, in Python one might have either:
result: str = parse(s)
if result is None:
# exception handling
or, more idiomatically:
try:
result: str = parse(s)
except ParseError:
# exception handling
The micro-optimization of not requiring a local variable and copying the return when using output variables can also be applied to conventional functions and return values by sufficiently sophisticated compilers.
The usual alternative to output parameters in C and related languages is to return a single data structure containing all return values.[13] For example, given a structure encapsulating width and height, one can write:
WidthHeight wh = f(x);
In object-oriented languages, instead of using input/output parameters, one can often use call by sharing, passing a reference to an object and then mutating the object, though not changing which object the variable refers to.[18]
See also
[edit]Notes
[edit]- ^ C and C++ are call by value, but if type is a reference (a C/C++ pointer or C++ reference), then setting the value of the reference can be used to produce call by reference style behavior.
References
[edit]- ^ "Passing Information to a Method or a Constructor (Learning the Java Language > Classes and Objects)". The Java™ Tutorials. Retrieved 2021-09-09.
Parameters refers to the list of variables in a method declaration. Arguments are the actual values that are passed in when the method is invoked. When you invoke a method, the arguments used must match the declaration's parameters in type and order.
- ^ Prata, Stephen (2004). C primer plus (5th ed.). Sams. pp. 276–277. ISBN 978-0-672-32696-7.
- ^ "Working Draft, Standard for Programming Language C++" (PDF). Open Standards. 2005-10-19. Archived from the original (PDF) on December 14, 2005. Retrieved 1 January 2018.
- ^ Gordon, Aaron. "Subprograms and Parameter Passing". rowdysites.msudenver.edu/~gordona. Archived from the original on 1 January 2018. Retrieved 1 January 2018.
- ^ Dollard, Kathleen. "Passing Arguments by Value and by Reference (Visual Basic)". Microsoft Learn. Retrieved 2018-10-27.
- ^ "The GNU C Programming Tutorial". crasseux.com. Retrieved 2018-10-27.
- ^ Meyer, Bertrand. Object-Oriented Software Construction, 2nd Edition, Prentice Hall, 1997, p 444.
- ^ Meyer, p. 96.
- ^ "Functions". gigamonkeys.com. Retrieved 2021-06-02.
- ^ "optional arguments". www.netlib.org. Retrieved 2021-06-02.
- ^ a b 8.2 Parameter Modes, "Rationale for the Design of the Ada® Programming Language"
- ^ 8. PL/SQL Subprograms: Specifying Subprogram Parameter Modes
- ^ a b Peter Hallam. "Why does C# have both 'ref' and 'out'?". Archived from the original on 2011-09-26.
- ^ ParameterDirection Enumeration
- ^ Functions — The Swift Programming Language (Swift 4.2)
- ^ 8. PL/SQL Subprograms: Passing Large Data Structures with the NOCOPY Compiler Hint
- ^ Int32.TryParse Method (String, Int32)
- ^ a b CA1021: Avoid out parameters
Parameter (computer programming)
View on GrokipediacalculateSum(int a, int b), a and b are parameters, and when invoked as calculateSum(5, 3), the integers 5 and 3 serve as arguments.[3] This separation promotes code clarity and flexibility, as parameters can be referenced throughout the function body, but their values are determined dynamically at runtime based on the arguments provided.[1]
Parameters can be passed using various mechanisms defined by the programming language, which determine how data is transferred and whether modifications within the function affect the original arguments.[4] The most common approaches include pass-by-value, where a copy of the argument's value is made for the parameter, ensuring the original data remains unchanged even if the parameter is modified inside the function; this protects the caller's data but may incur overhead for large objects.[5] In contrast, pass-by-reference passes the memory address of the argument, allowing the function to directly access and alter the original value, which is more efficient for large data but risks unintended side effects.[5] Other variants, such as pass-by-value-result (which copies in and out) or pass-by-name (which delays evaluation of the argument expression), are less common but appear in specific languages like Ada or Algol to handle complex scenarios.[4]
Function parameters also vary in type and usage across languages, including positional parameters (matched by order), keyword parameters (matched by name for clarity), default parameters (with predefined values if no argument is supplied), and variadic parameters (accepting a variable number of arguments).[2] These features enhance expressiveness; for example, languages like Python support both positional and keyword arguments, while C++ allows default values to simplify function calls.[3] Overall, parameters are fundamental to procedural and object-oriented programming, enabling abstraction, encapsulation, and the creation of maintainable software systems.[1]
Fundamentals
Definition and Role
In computer programming, a parameter is a variable in the declaration of a subroutine, function, or method that acts as a placeholder for values supplied by the caller at runtime. These formal parameters define the expected inputs for the subroutine and form part of its interface, allowing the subroutine to process varying data without altering its internal logic.[6][7] Parameters enable key principles of software design, including code reuse and modularity. By parameterizing subroutines, programmers can write reusable code blocks that operate on different inputs, reducing redundancy and simplifying maintenance. They also promote abstraction, separating the subroutine's external interface—what it does—from its internal implementation details, which enhances readability and allows changes to behavior without affecting calling code. This separation supports larger, more scalable programs by encapsulating functionality.[7][8] The concept of parameters originated in the mid-1950s with early high-level procedural languages, particularly Fortran, developed by John Backus and his team at IBM. Fortran I, released in 1957 for the IBM 704, introduced subroutines with formal parameters to pass data between the main program and reusable code segments, marking a shift from low-level assembly coding to more abstract, mathematical expression of computations. This innovation addressed the inefficiencies of manual programming on early computers, laying the foundation for parameter use in subsequent languages.[9][10] For illustration, in a C-like syntax, a simple function declaration might appear as:void calculate(int param) {
// Function body uses param as a local variable
}
void calculate(int param) {
// Function body uses param as a local variable
}
param is the formal parameter, receiving an integer value when the function is invoked.[11]
Parameters vs. Arguments
In computer programming, formal parameters are the named variables declared in a function or method signature, serving as placeholders that define the expected inputs for the subroutine. For instance, in a function definition, these parameters outline the structure and number of values the function will receive, without specifying their concrete values at the time of declaration.[12][13] In contrast, actual arguments—also known as actual parameters—are the specific expressions, values, or variables supplied when invoking the function or method. These arguments provide the runtime data that corresponds to each formal parameter, enabling the subroutine to perform its computation with concrete inputs. The distinction ensures clarity in code design, as formal parameters focus on the interface while actual arguments handle the invocation specifics.[14][15] During function execution, the binding process associates each actual argument with its corresponding formal parameter at runtime, creating a temporary mapping that allows the subroutine to access and manipulate the provided values within its scope. This binding is positional by default in most languages, matching arguments to parameters from left to right, and it supports modularity by isolating the subroutine's internal logic from the caller's context. Common confusions arise when the terms "parameter" and "argument" are used interchangeably in informal discussions or documentation, though precise usage avoids ambiguity in technical contexts.[15][12] Notably, terminology conventions can vary across languages. In Eiffel, the standard inverts the common usage: "formal arguments" refer to the named entities in the routine declaration (equivalent to formal parameters elsewhere), while "actual arguments" denote the values passed at the call site. This reversal highlights the importance of language-specific documentation to prevent misunderstandings.[16] The following examples illustrate the distinction in Python and Java, showing function/method declaration alongside invocation: Python:def add(a, b): # a and b are formal parameters
return a + b
result = add(3, 4) # 3 and 4 are actual arguments
def add(a, b): # a and b are formal parameters
return a + b
result = add(3, 4) # 3 and 4 are actual arguments
a and b act as placeholders in the definition, bound to the integers 3 and 4 upon calling.[13]
Java:
public int add(int a, int b) { // a and b are formal parameters
return a + b;
}
int result = add(3, 4); // 3 and 4 are actual arguments
public int add(int a, int b) { // a and b are formal parameters
return a + b;
}
int result = add(3, 4); // 3 and 4 are actual arguments
a and b as formal parameters, which receive the literal values 3 and 4 as arguments during the method call.[14]
Parameter Properties
Datatypes and Constraints
In computer programming, parameters in function signatures explicitly declare the expected datatypes to ensure type safety and clarity. For instance, in C++, a function signature such asint func(double x) specifies that the parameter x must be of type double, allowing the compiler to verify compatibility during declaration. This declaration forms part of the function's type, which includes the parameter types and influences overload resolution and calling conventions.[17]
Static typing enforces datatype constraints at compile time, preventing type mismatches before runtime execution. Languages like Java require parameters to declare specific types, such as void process(List<String> param) where param is a generic list constrained to strings, enabling the compiler to check assignments and method invocations against the declared type.[18] This compile-time verification catches errors early, as seen in Java's type system where incompatible arguments, like passing an integer to a string-typed parameter, result in compilation failures.[19]
In contrast, dynamic typing defers datatype checks to runtime, offering flexibility but requiring explicit validation if needed. Python functions declare parameters without mandatory types, as in def func(param):, but type hints like def func(param: str) -> None: provide optional annotations for tools to perform static analysis, while runtime checks use constructs like isinstance(param, str).[13] These hints, introduced via PEP 484, do not alter runtime behavior but support integrated development environments (IDEs) and type checkers like mypy for early error detection.[20]
Parameters often include additional constraints beyond basic datatypes to refine usage rules. For bounds, languages like C allow array parameters with size hints, such as void func(int arr[10]), though the size is not strictly enforced at runtime to avoid overhead; instead, programmers must ensure compliance to prevent buffer overflows. Nullability constraints address the risk of null references, with Java's Optional<T> wrapping potentially absent values in parameters, as in void handle(Optional<String> input), signaling that null is explicitly handled via methods like isPresent() rather than direct null checks.[21] Immutability hints, such as C++'s const qualifier in void func(const int& x), prevent modification of the parameter within the function, promoting safer code by enforcing read-only access without copying.
Modern languages have evolved toward more expressive parameterized types through generics, reducing reliance on casting and enhancing reusability. Java introduced generics in version 5 (J2SE 5.0), allowing type parameters like <T> in signatures such as public <T> void process(List<T> param), which the compiler erases at runtime (type erasure) while preserving compile-time safety for collections and methods.[18] This shift, motivated by the need for type-safe collections without runtime overhead,
Parameter Modes
Parameter modes in computer programming classify formal parameters based on the direction of data flow between the caller and the callee: input (in) parameters for reading data into the function, output (out) parameters for writing data from the function, and input/output (inout) parameters for both reading and writing.[22] This categorization helps define the intended usage and behavior of parameters, ensuring clarity in function design across languages.[23] Input parameters are the most common mode, allowing the function to receive and read data without modifying the original argument. They are typically declared as read-only to prevent unintended changes, serving as the default mode in most programming languages. For example, in C++, input parameters for complex types are often declared usingconst references, such as void process(const int& value), to enable efficient passing without copying while enforcing read-only access. This mode aligns with typed input parameters that specify datatypes and constraints for validation.
Output parameters are designed to convey results from the function back to the caller, often used when a single return value is insufficient for multiple outputs. The function must initialize these parameters before returning, and their initial values from the caller are typically ignored. A representative example in C++ is the declaration void getValue(int& result), where result acts as an output parameter to assign a computed value, such as result = 42;.[24] In languages with explicit modes, such as C#, output parameters are declared using the out keyword, as in bool TryParse(string s, out int result), allowing the method to return both a success flag and the parsed value.[25]
Input/output parameters support both reading initial values and writing modifications that affect the caller, making them suitable for operations requiring updates to the original data. This mode is prevalent in languages that support pass-by-reference semantics, where the parameter acts as an alias to the argument. For instance, in C++, a swap function can use references as void swap(int& a, int& b), where a and b act as inout parameters to exchange values. Swift declares inout parameters with the inout keyword, such as func increment(_ number: inout Int), enabling the function to modify the caller's variable directly.[26] Historically, languages like Pascal used var parameters for inout and output modes, as in procedure swap(var x, y: integer), to allow modifications without explicit mode keywords for inputs.[27]
Common use cases for output and inout parameters include returning error codes alongside results, such as status indicators in parsing functions, or swapping values without temporary variables.[28] Inout parameters are particularly useful for accumulating results in loops or updating collections, while output parameters facilitate returning multiple heterogeneous values, like coordinates or diagnostic information.[23] These modes enhance expressiveness in procedure-oriented designs but require careful documentation to avoid ambiguity in data flow.[22]
Passing Mechanisms
By Value
In pass-by-value semantics, the value of the argument is copied to a new memory location allocated for the parameter upon function invocation, ensuring that the parameter operates on an independent copy isolated from the original argument. This mechanism guarantees that modifications to the parameter within the function do not propagate back to the caller's variables, providing a clear boundary between the function's internal state and external data.[29] Pass-by-value is commonly employed for input parameters, where the intent is to read the value without altering the source.[30] A representative example occurs in the C programming language, which mandates pass-by-value for all non-pointer parameters as per its standard. Consider the function definitionvoid increment(int x) { x++; }; when invoked as int value = 5; increment(value);, the original value remains 5 post-call, demonstrating the copy's isolation.[31] This behavior aligns with C's design philosophy, where the language specification requires evaluating the argument and passing its computed value to the function, without any aliasing to the original.[29]
The strengths of pass-by-value lie in its inherent safety and conceptual simplicity: functions cannot inadvertently modify caller data, reducing bugs from side effects and making code easier to reason about and debug.[30] However, the copying process introduces performance drawbacks, particularly for large objects like structures or arrays in C, where duplicating substantial memory can lead to significant time and space overhead during function calls.[31]
Compilers address these limitations through optimizations tailored to small data types, such as integers or floats, often passing them directly in CPU registers instead of performing explicit stack-based copies, thereby eliminating runtime overhead while preserving semantics.[32] Historically, while early Fortran implementations defaulted to pass-by-reference for efficiency on limited hardware, later standards introduced explicit pass-by-value options via attributes like VALUE to enable similar isolation when needed.[33]
By Reference
In pass-by-reference, a parameter acts as an alias for the argument's memory location, providing direct access without creating a copy of the data. This mechanism binds the formal parameter to the actual argument's address, so any modifications to the parameter within the function directly alter the original argument in the caller's scope. Unlike pass-by-value, which isolates the argument through copying, pass-by-reference enables bidirectional data flow, allowing both input and output through the same parameter.[34] This aliasing is implemented differently across languages. In C++, references are explicitly declared using the& symbol, creating a synonym for the argument that permits efficient modification of large structures. For example, the function void increment(int& x) { x++; } called with int y = 5; increment(y); results in y becoming 6, as the reference directly accesses y's location.[11][35]
Python employs a form of pass-by-reference through object sharing, where arguments are passed as references to objects; mutable objects like lists can thus be modified in place. Consider def append_item(lst): lst.append(1); my_list = [2, 3]; append_item(my_list);—after the call, my_list becomes [2, 3, 1], demonstrating how the function alters the caller's object. However, immutable objects like integers behave as if passed by value, since reassigning them creates a new object without affecting the original.[36]
In Java, all parameters are passed by value, but references to objects are values that can be dereferenced to modify the object's state. Primitive types like int are copied, preventing changes to the original, while object references allow field updates to propagate. For instance, a method void move(Circle c, int dx) { c.setX(c.getX() + dx); } invoked with an existing Circle instance shifts its position, as the reference points to the same object. Primitives, however, remain unchanged: void add(int n) { n += 1; } does not increment the caller's variable.[14]
The primary advantages of pass-by-reference include improved efficiency, particularly for large data structures, as only the address is passed rather than duplicating the entire object, reducing time and memory overhead. It also supports input/output parameter modes, enabling functions to both read from and write to the caller's data without multiple return values.[34][35]
Drawbacks arise from potential unintended side effects, where modifications in one part of the code unexpectedly alter data elsewhere, complicating debugging and program reasoning. Aliasing can introduce bugs, such as when multiple parameters refer to the same object, leading to non-deterministic behavior or violations of expected isolation.[34][11]
By Value Result and Copies
Pass-by-value-result, also known as copy-in copy-out, is a hybrid parameter passing mechanism in which the value of the actual parameter is copied to the formal parameter upon entry to the subprogram (copy-in), allowing the subprogram to read and modify a local copy. Upon completion of the subprogram, the final value of the formal parameter is copied back to the actual parameter (copy-out), enabling changes to propagate to the caller. This method provides input-output capabilities similar to pass-by-reference but uses copies to isolate the subprogram's modifications from the caller's memory, avoiding direct aliasing during execution.[34][37] In Ada, thein out parameter mode implements value-result semantics for types that are passed by copy, such as elementary types and small aggregates. The initial value is copied into the formal parameter before execution, and any modifications are copied back to the actual parameter afterward, ensuring the caller's object reflects updates without shared access during the call. Similarly, early versions of Fortran, such as Fortran IV, employed value-result passing, where arguments were copied in and out to support modifiable parameters while maintaining separation from the caller's environment; modern Fortran defaults to pass-by-reference but supports value passing via attributes for similar effects in specific cases.[38][37][39]
The primary advantage of pass-by-value-result is its ability to prevent aliasing issues that arise in pass-by-reference, such as unintended side effects from shared references to the same object, thereby promoting clearer data flow and safer subprogram behavior. However, it incurs the overhead of two copies per parameter, which can be inefficient for large data structures like arrays or records, potentially impacting performance in memory-intensive applications. Additionally, it introduces copy-in-copy-out anomalies: when the same actual parameter is passed multiple times to a subprogram, the unspecified order of copy-out operations can lead to undefined or unpredictable final values in the caller.[37][40][34]
In modern contexts, pass-by-value-result is analogous to data transfer mechanisms in parallel programming environments like GPU computing, where input data is copied into device memory for execution and results are copied back to the host to ensure isolation and prevent race conditions across concurrent operations.[37]
Advanced Features
Default Arguments
Default arguments, also known as default parameters, provide predefined values for function or method parameters, allowing calls to omit those arguments while using the defaults instead.[41] This mechanism enhances function flexibility by making certain parameters optional without requiring multiple overloaded versions of the same function. For instance, in Python, a function can be defined asdef greet(name="World"): print(f"Hello, {name}!"), where invoking greet() outputs "Hello, World!" and greet("Alice") uses the provided argument.[41]
In most programming languages supporting default arguments, they must appear in trailing positions within the parameter list, meaning all subsequent parameters also require defaults in the same declaration. This positional requirement ensures unambiguous argument binding during calls, as earlier parameters without defaults must always be supplied. For example, in C++, a declaration like void func(int x, int y = 10, int z = 20); permits calls such as func(5) (using y=10, z=20) or func(5, 15) (using z=20), but not func(5, , 25) due to the trailing constraint.
Default arguments were first introduced in C++ during its early development as "C with Classes" in the early 1980s, becoming a core feature by the language's initial release in 1985.[42] This innovation has since been adopted in many languages, including JavaScript starting with ECMAScript 2015 (ES6), where syntax like function example(param = "default") { return param; } initializes parameters to defaults if undefined values are passed.[43]
The primary advantages of default arguments include reducing code boilerplate by avoiding repetitive function definitions for common cases and improving API usability through simpler invocation patterns.[41] However, drawbacks arise from the strict positional ordering, which can complicate adding new parameters without breaking existing calls, and from evaluation semantics where defaults are typically computed once at definition time. In Python, this leads to pitfalls with mutable defaults, such as lists, which are shared across all calls and can accumulate unintended modifications; for example, def append_to(element, to=[]): to.append(element); return to results in subsequent calls like append_to(1) and append_to(2) yielding [1, 2] instead of separate lists.[41] To mitigate this, immutable defaults or runtime checks (e.g., using None as a sentinel) are recommended.[41]
Variadic Parameters
Variadic parameters, also known as variable arguments or varargs, allow a function to accept a variable number of arguments beyond any fixed parameters, providing flexibility in function calls without requiring multiple overloaded versions.[44] This feature is implemented through special syntax in various programming languages, enabling developers to handle dynamic argument lists efficiently. For instance, in C, variadic functions use the ellipsis (...) in the parameter list, combined with the <stdarg.h> header for accessing arguments via va_list, va_start, va_arg, and va_end macros, as standardized in ANSI C (1989) and ISO/IEC 9899:1990 (C90). This mechanism originated as a way to support functions like printf, where the format string dictates the number and types of subsequent arguments.[45]
In modern languages, rest parameters represent a common type of variadic mechanism, typically capturing trailing arguments as an array after fixed parameters. Python employs *args to collect positional arguments into a tuple, allowing functions like def sum(*args): return sum(args) to compute totals flexibly.[46] Similarly, JavaScript uses the rest parameter syntax with ... (introduced in ECMAScript 2015), as in function sum(...args) { return args.reduce((a, b) => a + b, 0); }, which gathers remaining arguments into an array while preserving type information at runtime.[47] Java's varargs, added in J2SE 5.0, use Type... (e.g., void print(Object... args)), treating variable arguments as an array of the specified type, which simplifies calls to utility methods like logging or array operations.[44]
C++ supports both legacy variadic functions (similar to C, using ... and va_list) and more advanced variadic templates, introduced in ISO/IEC 14882:2011 (C++11), which use parameter packs like template<typename... Args> void func(Args... args); for compile-time expansion.[48] This allows full type safety and recursion over argument packs, enabling generic utilities such as perfect forwarding in std::forward or tuple construction in [std::make_tuple](/page/Tuple). Variadic templates differ from rest parameters by applying to the entire parameter list, including fixed ones, and supporting heterogeneous types without runtime overhead.
The primary advantage of variadic parameters lies in their flexibility for implementing general-purpose utilities, such as aggregation functions (e.g., summing arbitrary numbers) or formatted output like printf, reducing code duplication across similar operations.[45] They promote reusable designs in libraries, as seen in C's standard I/O functions or Java's Arrays.asList(Object... a). However, they introduce significant drawbacks, particularly a loss of type safety; in C-style variadics, argument types and counts are not enforced at compile time, relying on runtime conventions that can lead to buffer overflows or undefined behavior if mismatched.[49] Debugging becomes challenging due to opaque argument access, and performance may suffer from array creation or pack expansion, though variadic templates mitigate some issues through compile-time resolution.[50] Despite these cons, when used judiciously with fixed sentinels or type-checked wrappers, variadics remain essential for low-level systems programming and dynamic interfaces.
Named and Keyword Arguments
Named and keyword arguments, also known as named parameters in some contexts, allow function calls to specify arguments by associating values with parameter names rather than relying solely on positional order. This mechanism enhances flexibility in argument passing by enabling developers to identify the purpose of each value explicitly. For instance, in Python, a function call might appear asfunc(x=1, y=2), where x and y are parameter names matched to their corresponding values.[51] Similarly, in C#, named arguments use the syntax method(parameterName: value), such as PrintOrderDetails(productName: "Red Mug", orderNum: 31), permitting arguments to be supplied in any order while maintaining clarity.[52] In PowerShell, named parameters are invoked with a hyphen prefix, like Get-ChildItem -Path C:\techdocs -Exclude *.ppt, supporting order-independent specification for cmdlets and functions.[53]
The primary advantages of named and keyword arguments include order independence, which reduces errors in functions with multiple parameters by allowing values to be provided in a logical sequence rather than a strict positional one.[51] They also promote self-documenting code, as the parameter names reveal the intent of each argument, improving readability especially in complex calls with many options.[52] Furthermore, this approach facilitates easy overriding of default arguments; for example, in Python, defaults can be skipped or selectively overridden using names, such as parrot(voltage=1000) to use the default state while specifying voltage.[54] In C# and PowerShell, named arguments similarly allow omission of optional parameters by targeting only the desired ones, streamlining calls without altering function signatures.[52][53]
Despite these benefits, named and keyword arguments introduce some drawbacks, such as increased verbosity, which can make simple calls longer and harder to write compared to concise positional equivalents.[55] Additionally, without proper validation—though most languages enforce name matching at compile or runtime—misspelled parameter names can lead to errors, like a TypeError in Python or a compile-time failure in C#.[51][52] In PowerShell, while names are validated against defined parameters, dynamic or aliased usage may still risk mismatches if not handled carefully.[53]
Named arguments are particularly useful in conjunction with default values, as they permit skipping leading positional parameters entirely when all arguments are named, a feature supported in Python and C# for cleaner invocation of functions with optional leading defaults.[51][52] This can also extend briefly to variadic scenarios, such as Python's **kwargs for capturing excess named arguments into a dictionary.[46]
Paradigms and Variations
In Functional Programming
In functional programming, parameters are treated as immutable inputs to pure functions, ensuring that computations depend solely on the arguments provided and produce no side effects. This immutability eliminates the need for output modes like pass-by-reference for modification, fostering referential transparency where function applications can be replaced by their results without altering program behavior.[56] Such design principles, emphasized in languages like Haskell, align with the paradigm's focus on declarative expressions over imperative assignments.[57] Higher-order functions, a cornerstone of functional programming, accept other functions as parameters to abstract common patterns and promote code reuse. In Haskell, themap function exemplifies this by taking a function f and a list xs as parameters, returning a new list with f applied to each element:
map (* 2) [1, 2, 3] -- Results in [2, 4, 6]
map (* 2) [1, 2, 3] -- Results in [2, 4, 6]
mapcar apply a function parameter to successive elements of one or more lists, enabling similar abstractions while treating functions as first-class objects via constructs like lambda.[59]
Currying further refines parameter handling by converting multi-argument functions into a chain of single-argument functions, enabling partial application where fewer arguments than expected are supplied to yield a new function. For instance, in Haskell, the addition function add :: Num a => a -> a -> a (defined as add x y = x + y) can be partially applied as add 3, producing a function of type Num a => a -> a that adds 3 to its input; thus, (add 3) 5 evaluates to 8.[60] Multiple parameters are managed through this curried form or by grouping via tuples, such as defining a function (Int, Int) -> Int for paired inputs, avoiding variadic mechanisms in favor of compositional chains.[61]
In Haskell, lazy evaluation impacts parameter processing by deferring argument computation until their values are demanded, representing unevaluated expressions as thunks to optimize resource use and support infinite data structures.[62] Lisp, originating as one of the earliest functional languages, carries a legacy of dynamic scoping where unbound variables in parameters resolve to the most recent dynamic binding in the call stack, though contemporary standards like Common Lisp default to lexical scoping for predictability in functional code.[63]
In Object-Oriented Programming
In object-oriented programming (OOP), method parameters serve as inputs to instance methods, which operate on the state of specific objects. A key feature is the implicit parameter representing the current object instance, often referred to as "this" in languages like Java or "self" in Python. In Java, the "this" keyword explicitly refers to the current instance, allowing methods to access or modify the object's fields, especially when parameter names shadow field names; for example, in a setter method likepublic void setAge(int age) { this.age = age; }, "this" disambiguates the parameter from the instance variable.[64] Similarly, in Python, the first parameter of an instance method is conventionally named "self" and is implicitly passed when the method is called on an instance, enabling access to instance attributes such as def set_age(self, age): self.age = age.[65] This implicit parameter distinguishes OOP methods from standalone functions by tying them to object state and behavior.[66]
Constructors in OOP are special methods that initialize new object instances and typically accept parameters to set initial attribute values. For instance, in Java, a parameterized constructor might be defined as public [Person](/page/Person)(String name, int age) { this.name = name; this.age = age; }, invoked via [Person](/page/Person) p = new [Person](/page/Person)("Alice", 30);, ensuring the object is properly configured upon creation. These parameters promote encapsulation by allowing controlled initialization without exposing internal fields directly. In C#, constructors similarly use parameters for flexible object creation, such as public [Person](/page/Person)(string name, int age) { Name = name; Age = age; }.[67]
Polymorphism in OOP often leverages parameters through method overloading, where multiple methods share the same name but differ in parameter types, number, or order, enabling compile-time resolution based on the call signature. In Java, for example, a class might overload a draw method as public void draw([Circle](/page/Circle) c) and public void draw([Rectangle](/page/Rectangle) r), allowing the same method name to handle different shapes polymorphically.[66] This supports ad-hoc polymorphism without runtime dispatch, contrasting with overriding in inheritance hierarchies. Abstract methods in Java interfaces further utilize parameters to define contracts; for instance, an interface might declare void process([String](/page/String) data);, which implementing classes must provide with matching signatures, ensuring polymorphic behavior across types.[68]
Due to encapsulation principles in OOP, output from methods is typically handled via return values or public properties/getters rather than explicit output parameters, minimizing direct state mutation from outside the object. Encapsulation bundles data and methods within classes, using access modifiers like private fields with public getters (e.g., public int getAge() { return age; }) to control access and maintain internal consistency.[69] This approach avoids the need for pass-by-reference output parameters common in procedural languages, favoring immutable returns or property setters for safer interactions. In Python, properties achieve similar encapsulation, as in @property def age([self](/page/Self)): return [self](/page/Self)._age, providing read access without exposing the underlying attribute.[65]
Language-specific conventions highlight parameter variations in OOP. Java interfaces often include abstract methods with parameters to enforce polymorphic implementations, such as in List where add(E e) requires subclasses like ArrayList to handle element insertion uniformly.[68] In Python, the @classmethod decorator defines methods that receive the class as the implicit first parameter (conventionally cls) instead of an instance, useful for factory methods like cls.create_from_dict(data) that return new instances without invoking __init__ directly.[70] These features integrate parameters with OOP's emphasis on modularity and extensibility.
Language-Specific Conventions
In the Eiffel programming language, parameters in routine declarations are referred to as formal arguments, which define the expected input types and names, while the values supplied during a call are known as actual arguments.[71] Routines, which encompass procedures and functions, incorporate Design by Contract principles where preconditions—expressed viarequire clauses—specify conditions that the caller must satisfy on formal arguments before execution, such as ensuring a deposit amount is non-negative in a banking routine.[72] These preconditions are not checked by the routine itself but serve as documentation and can be enforced at runtime through compiler options, emphasizing client responsibility for valid inputs.[71]
JavaScript introduced rest parameters in ES6 (ECMAScript 2015), allowing functions to capture a variable number of arguments as an array using the ... syntax, which must be the final parameter and enables variadic behavior without relying on the legacy arguments object.[47] The spread operator (...) complements this by expanding arrays or iterables into individual arguments during function calls, facilitating concise handling of dynamic inputs. Prior to ES6, true default parameters did not exist; developers instead used conditional checks within the function body, such as verifying if an argument was undefined before assigning a fallback value.[43] In modern JavaScript, async functions—declared with the async keyword—accept standard parameters but implicitly return promises, allowing parameters to include promises that are awaited inside the function for asynchronous processing without altering the parameter passing mechanism itself.[73]
Rust's parameter conventions are governed by its ownership model, where passing a value by name transfers ownership, rendering the original inaccessible to prevent memory errors, while references (&T for immutable and &mut T for mutable) enable borrowing without transfer.[74] The borrow checker, a core compiler component, enforces these rules at compile time by disallowing multiple mutable borrows or mixing mutable and immutable borrows on the same data simultaneously, ensuring thread safety and preventing issues like data races or use-after-free.[74] This approach contrasts with languages using pointers, as Rust's lifetimes track reference validity, requiring explicit annotation for complex parameter interactions.
In Go, functions support multiple return values as a convention for handling outputs like results and errors together, specified in the signature as a parenthesized list (e.g., func divide(a, b int) (int, [error](/page/Error))), where the last value is often an error type to indicate failure without exceptions.[75] This multiple-return idiom effectively simulates out-parameters by allowing callers to receive and unpack values positionally, such as quotient, err := divide(9, 3), promoting explicit error checking as a language norm rather than separate parameter mechanisms.[76]
COBOL's parameter passing in subprogram calls relies on the USING clause within the CALL statement, which specifies data items or procedure names to be shared between programs, defaulting to pass-by-reference for efficiency in legacy systems.[77] Additional phrases like BY CONTENT, BY REFERENCE, or BY VALUE can modify this behavior, with RETURNING used for output parameters in some dialects, reflecting the language's emphasis on procedural data exchange in business applications.[78] These clauses, introduced in early standards like ANSI COBOL 1968, remain in modern implementations but are considered outdated compared to higher-level abstractions in contemporary languages.[79]