Why should default parameters be added last in C++ functions? - c++

Why should default parameters be added last in C++ functions?

To simplify the language definition and keep code readable.
void foo(int x = 2, int y);
To call that and take advantage of the default value, you'd need syntax like this:
foo(, 3);
Which was probably felt to be too weird. Another alternative is specifying names in the argument list:
foo(y : 3);
A new symbol would have to be used because this already means something:
foo(y = 3); // assign 3 to y and then pass y to foo.
The naming approach was considered and rejected by the ISO committee because they were uncomfortable with introducing a new significance to parameter names outside of the function definition.
If you're interested in more C++ design rationales, read The Design and Evolution of C++ by Stroustrup.

If you define the following function:
void foo( int a, int b = 0, int c );
How would you call the function and supply a value for a and c, but leave b as the default?
foo( 10, ??, 5 );
Unlike some other languages (eg, Python), function arguments in C/C++ can not be qualified by name, like the following:
foo( a = 10, c = 5 );
If that were possible, then the default arguments could be anywhere in the list.

Imagine you had a function with this prototype:
void testFunction(bool a = false, bool b = true, bool c);
Now suppose I called the function like this:
testFunction(true, false);
How is the compiler supposed to figure out which parameters I meant to supply values for?

As most of the answers point out, having default parameters potentially anywhere in the parameter list increases the complexity and ambiguity of function calls (for both the compiler and probably more importantly for the users of the function).
One nice thing about C++ is that there's often a way to do what you want (even if it's not always a good idea). If you want to have default arguments for various parameter positions, you can almost certainly do this by writing overloads that simply turn around and call the fully-parameterized function inline:
int foo( int x, int y);
int foo( int y) {
return foo( 0, y);
}
And there you have the equivalent of:
int foo( int x = 0, int y);

As a general rule function parameters are processed by the compiler and placed on the stack in right to left order. Therefore it makes sense that any parameters with default values should be evaluated first.
(This applieds to __cdecl, which tends to be the default for VC++ and __stdcall function declarations).

Its because it uses the relative position of arguments to find to which parameters they correspond.
It could have used the types to identify that an optional parameter was not given. But implicit conversion could interfere with it. Another problem would be programming errors that could be interpreted as optional arguments drop out instead of missing argument error.
In order to allow any argument to become optional, there should be a way to identify the arguments to make sure there is no programming error or to remove ambiguities. This is possible in some languages, but not in C++.

Another thing that the standards committee had to consider was how default parameters interacts with other features, like overloaded functions, template resolution, and name lookup. These features interact in very complex and hard to describe ways already. Making default parameters be able to appear anywhere would only increase the complexity.

It is a matter about call convention.
Call Convention:
When you call a function, the parameters are pushed in stack from right to left.
e.g.
fun(int a, int b, int c);
the stack is like this:
a
b
c
so, if you set the default value from left to right like this:
fun(int a = 1, int b = 2, int c);
and call like this:
fun(4,5);
your call means set a = 4, b = 5, and c = no value; // which is wrong!
if you declare the function like this:
fun(int a, int b = 2, int c = 3);
and call like this:
fun(4, 5);
your call means set a = 4, b = 5, and c = default value(3); // which is right!
In conclusion, you should put the default value from right to left.

Jing Zeng is correct. I would like to add my remarks here. When a function is called, the arguments are pushed onto the stack from right to left. For example, let's say you have this arbitrary function.
int add(int a, int b) {
int c;
c = a + b;
return c;
}
Here is the stack frame for the function:
------
b
------
a
------
ret
------
c
------
This diagram above is the stack frame for this function! As you can see, first b is pushed onto the stack, then a is pushed onto the stack. After that the function return address is pushed onto the stack. The function return address holds the location in main() from where the function was originally called, and after the function is done executing, the execution of the program goes to that function's return address. Then any local variables such as c are pushed onto the stack.
Now the key thing is that arguments are pushed onto the stack from right to left. Basically any default parameters that are supplied are literal values, which are stored in the code section of an executable. When the program execution encounters a default parameter without a corresponding argument, it pushes that literal value onto the top of the stack. Then it looks at a and pushes the argument's value onto the top of the stack. The stack pointer always points to the top of the stack, your most recently pushed variable. So any literal values you pushed onto the stack as default parameters are "behind" the stack pointer.
It was probably more efficient for the compiler to quickly first push arbitrary default literal values onto the stack first, since they're not stored in a memory location, and build up the stack quickly. Think about what would have been if the variables would have been pushed onto the stack first, and then the literals. Accessing a memory location for the CPU takes up a relatively long time compared to pulling a literal value out of a circuit or CPU register. Since it takes more time to push variables onto the stack vs. literals, the literals would have to wait, then the return address would have to wait, and the local variables would have to wait as well. It's probably not a big concern in efficiency, but that's just my theory for why default arguments are always in the rightmost positions of a function header in C++. It means that the compiler was designed as such.

Related

C/C++ compiler optimisations: should I prefer creating new variables, re-using existing ones, or avoiding variables altogether?

This is something I've always wondered: is it easier for the compiler to optimise functions where existing variables are re-used, where new (ideally const) intermediate variables are created, or where creating variables is avoided in favour of directly using expressions?
For example, consider the functions below:
// 1. Use expression as and when needed, no new variables
void MyFunction1(int a, int b)
{
SubFunction1(a + b);
SubFunction2(a + b);
SubFunction3(a + b);
}
// 2. Re-use existing function parameter variable to compute
// result once, and use result multiple times.
// (I've seen this approach most in old-school C code)
void MyFunction2(int a, int b)
{
a += b;
SubFunction1(a);
SubFunction2(a);
SubFunction3(a);
}
// 3. Use a new variable to compute result once,
// and use result multiple times.
void MyFunction3(int a, int b)
{
int sum = a + b;
SubFunction1(sum);
SubFunction2(sum);
SubFunction3(sum);
}
// 4. Use a new const variable to compute result once,
// and use result multiple times.
void MyFunction4(int a, int b)
{
const int sum = a + b;
SubFunction1(sum);
SubFunction2(sum);
SubFunction3(sum);
}
My intuition is that:
In this particular situation, function 4 is easiest to optimise because it explicitly states the intention for the use of the data. It is telling the compiler: "We are summing the two input arguments, the result of which will not be modified, and we are passing on the result in an identical way to each subsequent function call." I expect that the value of the sum variable will just be put into a register, and no actual underlying memory access will occur.
Function 1 is the next easiest to optimise, though it requires more inference on the part of the compiler. The compiler must spot that a + b is used in an identical way for each function call, and it must know that the result of a + b is identical each time that expression is used. I would still expect the result of a + b to be put into a register rather than committed to memory. However, if the input arguments were more complicated than plain ints, I can see this being more difficult to optimise (rules on temporaries would apply for C++).
Function 3 is the next easiest after that: the result is not put into a const variable, but the compiler can see that sum is not modified anywhere in the function (assuming that the subsequent functions do not take a mutable reference to it), so it can just store the value in a register similarly to before. This is less likely than in function 4's case, though.
Function 4 gives the least assistance for optimisations, since it directly modifies an incoming function argument. I'm not 100% sure what the compiler would do here: I don't think it's unreasonable to expect it to be intelligent enough to spot that a is not used anywhere else in the function (similarly to sum in function 3), but I wouldn't guarantee it. This could require modifying stack memory depending on how the function arguments are passed in (I'm not too familiar with the ins and outs of how function calls work at that level of detail).
Are my assumptions here correct? Are there more factors to take into account?
EDIT: A couple of clarifications in response to comments:
If C and C++ compilers would approach the above examples in different ways, I'd be interested to know why. I can understand that C++ would optimise things differently depending on what constraints there are on whichever objects might be inputs to these functions, but for primitive types like int I would expect them to use identical heuristics.
Yes, I could compile with optimisations and look at the assembly output, but I don't know assembly, hence I'm asking here instead.
Good modern compilers generally do not “care” about the names you use to store values. They perform lifetime analyses of the values and generate code based on that. For example, given:
int x = complicated expression 0;
... code using x
x = complicated expression 1;
... code using x
the compiler will see that complicated expression 0 is used in the first section of code and complicated expression 1 is used in the second section of code, and the name x is irrelevant. The result will be the same as if the code used different names:
int x0 = complicated expression 0;
... code using x0
int x1 = complicated expression 1;
... code using x1
So there is no point in reusing a variable for a different purpose; it will not help the compiler save memory or otherwise optimize.
Even if the code were in a loop, such as:
int x;
while (some condition)
{
x = complicated expression;
... code using x
}
the compiler will see that complicated expression is born at the beginning of the loop body and ends by the end of the loop body.
What this means is you do not have to worry about what the compiler will do with the code. Instead, your decisions should be guided mostly by what is clearer to write and more likely to avoid bugs:
Avoid reusing a variable for more than one purpose. For example, if somebody is later updating your function to add a new feature, they might miss the fact you have changed the function parameter with a += b; and use a later in the code as if it still contained the original parameter.
Do freely create new variables to hold repeated expressions. int sum = a + b; is fine; it expresses the intent and makes it clearer to readers when the same expression is used in multiple places.
Limit the scope of variables (and identifiers generally). Declare them only in the innermost scope where they are needed, such as inside a loop rather than outside. The avoids a variable being used accidentally where it is no longer appropriate.

why all subsequent arguments should have default values once a default value is provided? [duplicate]

Why should default parameters be added last in C++ functions?
To simplify the language definition and keep code readable.
void foo(int x = 2, int y);
To call that and take advantage of the default value, you'd need syntax like this:
foo(, 3);
Which was probably felt to be too weird. Another alternative is specifying names in the argument list:
foo(y : 3);
A new symbol would have to be used because this already means something:
foo(y = 3); // assign 3 to y and then pass y to foo.
The naming approach was considered and rejected by the ISO committee because they were uncomfortable with introducing a new significance to parameter names outside of the function definition.
If you're interested in more C++ design rationales, read The Design and Evolution of C++ by Stroustrup.
If you define the following function:
void foo( int a, int b = 0, int c );
How would you call the function and supply a value for a and c, but leave b as the default?
foo( 10, ??, 5 );
Unlike some other languages (eg, Python), function arguments in C/C++ can not be qualified by name, like the following:
foo( a = 10, c = 5 );
If that were possible, then the default arguments could be anywhere in the list.
Imagine you had a function with this prototype:
void testFunction(bool a = false, bool b = true, bool c);
Now suppose I called the function like this:
testFunction(true, false);
How is the compiler supposed to figure out which parameters I meant to supply values for?
As most of the answers point out, having default parameters potentially anywhere in the parameter list increases the complexity and ambiguity of function calls (for both the compiler and probably more importantly for the users of the function).
One nice thing about C++ is that there's often a way to do what you want (even if it's not always a good idea). If you want to have default arguments for various parameter positions, you can almost certainly do this by writing overloads that simply turn around and call the fully-parameterized function inline:
int foo( int x, int y);
int foo( int y) {
return foo( 0, y);
}
And there you have the equivalent of:
int foo( int x = 0, int y);
As a general rule function parameters are processed by the compiler and placed on the stack in right to left order. Therefore it makes sense that any parameters with default values should be evaluated first.
(This applieds to __cdecl, which tends to be the default for VC++ and __stdcall function declarations).
Its because it uses the relative position of arguments to find to which parameters they correspond.
It could have used the types to identify that an optional parameter was not given. But implicit conversion could interfere with it. Another problem would be programming errors that could be interpreted as optional arguments drop out instead of missing argument error.
In order to allow any argument to become optional, there should be a way to identify the arguments to make sure there is no programming error or to remove ambiguities. This is possible in some languages, but not in C++.
Another thing that the standards committee had to consider was how default parameters interacts with other features, like overloaded functions, template resolution, and name lookup. These features interact in very complex and hard to describe ways already. Making default parameters be able to appear anywhere would only increase the complexity.
It is a matter about call convention.
Call Convention:
When you call a function, the parameters are pushed in stack from right to left.
e.g.
fun(int a, int b, int c);
the stack is like this:
a
b
c
so, if you set the default value from left to right like this:
fun(int a = 1, int b = 2, int c);
and call like this:
fun(4,5);
your call means set a = 4, b = 5, and c = no value; // which is wrong!
if you declare the function like this:
fun(int a, int b = 2, int c = 3);
and call like this:
fun(4, 5);
your call means set a = 4, b = 5, and c = default value(3); // which is right!
In conclusion, you should put the default value from right to left.
Jing Zeng is correct. I would like to add my remarks here. When a function is called, the arguments are pushed onto the stack from right to left. For example, let's say you have this arbitrary function.
int add(int a, int b) {
int c;
c = a + b;
return c;
}
Here is the stack frame for the function:
------
b
------
a
------
ret
------
c
------
This diagram above is the stack frame for this function! As you can see, first b is pushed onto the stack, then a is pushed onto the stack. After that the function return address is pushed onto the stack. The function return address holds the location in main() from where the function was originally called, and after the function is done executing, the execution of the program goes to that function's return address. Then any local variables such as c are pushed onto the stack.
Now the key thing is that arguments are pushed onto the stack from right to left. Basically any default parameters that are supplied are literal values, which are stored in the code section of an executable. When the program execution encounters a default parameter without a corresponding argument, it pushes that literal value onto the top of the stack. Then it looks at a and pushes the argument's value onto the top of the stack. The stack pointer always points to the top of the stack, your most recently pushed variable. So any literal values you pushed onto the stack as default parameters are "behind" the stack pointer.
It was probably more efficient for the compiler to quickly first push arbitrary default literal values onto the stack first, since they're not stored in a memory location, and build up the stack quickly. Think about what would have been if the variables would have been pushed onto the stack first, and then the literals. Accessing a memory location for the CPU takes up a relatively long time compared to pulling a literal value out of a circuit or CPU register. Since it takes more time to push variables onto the stack vs. literals, the literals would have to wait, then the return address would have to wait, and the local variables would have to wait as well. It's probably not a big concern in efficiency, but that's just my theory for why default arguments are always in the rightmost positions of a function header in C++. It means that the compiler was designed as such.

Why are the default arguments provided for trailing arguments only [duplicate]

Why should default parameters be added last in C++ functions?
To simplify the language definition and keep code readable.
void foo(int x = 2, int y);
To call that and take advantage of the default value, you'd need syntax like this:
foo(, 3);
Which was probably felt to be too weird. Another alternative is specifying names in the argument list:
foo(y : 3);
A new symbol would have to be used because this already means something:
foo(y = 3); // assign 3 to y and then pass y to foo.
The naming approach was considered and rejected by the ISO committee because they were uncomfortable with introducing a new significance to parameter names outside of the function definition.
If you're interested in more C++ design rationales, read The Design and Evolution of C++ by Stroustrup.
If you define the following function:
void foo( int a, int b = 0, int c );
How would you call the function and supply a value for a and c, but leave b as the default?
foo( 10, ??, 5 );
Unlike some other languages (eg, Python), function arguments in C/C++ can not be qualified by name, like the following:
foo( a = 10, c = 5 );
If that were possible, then the default arguments could be anywhere in the list.
Imagine you had a function with this prototype:
void testFunction(bool a = false, bool b = true, bool c);
Now suppose I called the function like this:
testFunction(true, false);
How is the compiler supposed to figure out which parameters I meant to supply values for?
As most of the answers point out, having default parameters potentially anywhere in the parameter list increases the complexity and ambiguity of function calls (for both the compiler and probably more importantly for the users of the function).
One nice thing about C++ is that there's often a way to do what you want (even if it's not always a good idea). If you want to have default arguments for various parameter positions, you can almost certainly do this by writing overloads that simply turn around and call the fully-parameterized function inline:
int foo( int x, int y);
int foo( int y) {
return foo( 0, y);
}
And there you have the equivalent of:
int foo( int x = 0, int y);
As a general rule function parameters are processed by the compiler and placed on the stack in right to left order. Therefore it makes sense that any parameters with default values should be evaluated first.
(This applieds to __cdecl, which tends to be the default for VC++ and __stdcall function declarations).
Its because it uses the relative position of arguments to find to which parameters they correspond.
It could have used the types to identify that an optional parameter was not given. But implicit conversion could interfere with it. Another problem would be programming errors that could be interpreted as optional arguments drop out instead of missing argument error.
In order to allow any argument to become optional, there should be a way to identify the arguments to make sure there is no programming error or to remove ambiguities. This is possible in some languages, but not in C++.
Another thing that the standards committee had to consider was how default parameters interacts with other features, like overloaded functions, template resolution, and name lookup. These features interact in very complex and hard to describe ways already. Making default parameters be able to appear anywhere would only increase the complexity.
It is a matter about call convention.
Call Convention:
When you call a function, the parameters are pushed in stack from right to left.
e.g.
fun(int a, int b, int c);
the stack is like this:
a
b
c
so, if you set the default value from left to right like this:
fun(int a = 1, int b = 2, int c);
and call like this:
fun(4,5);
your call means set a = 4, b = 5, and c = no value; // which is wrong!
if you declare the function like this:
fun(int a, int b = 2, int c = 3);
and call like this:
fun(4, 5);
your call means set a = 4, b = 5, and c = default value(3); // which is right!
In conclusion, you should put the default value from right to left.
Jing Zeng is correct. I would like to add my remarks here. When a function is called, the arguments are pushed onto the stack from right to left. For example, let's say you have this arbitrary function.
int add(int a, int b) {
int c;
c = a + b;
return c;
}
Here is the stack frame for the function:
------
b
------
a
------
ret
------
c
------
This diagram above is the stack frame for this function! As you can see, first b is pushed onto the stack, then a is pushed onto the stack. After that the function return address is pushed onto the stack. The function return address holds the location in main() from where the function was originally called, and after the function is done executing, the execution of the program goes to that function's return address. Then any local variables such as c are pushed onto the stack.
Now the key thing is that arguments are pushed onto the stack from right to left. Basically any default parameters that are supplied are literal values, which are stored in the code section of an executable. When the program execution encounters a default parameter without a corresponding argument, it pushes that literal value onto the top of the stack. Then it looks at a and pushes the argument's value onto the top of the stack. The stack pointer always points to the top of the stack, your most recently pushed variable. So any literal values you pushed onto the stack as default parameters are "behind" the stack pointer.
It was probably more efficient for the compiler to quickly first push arbitrary default literal values onto the stack first, since they're not stored in a memory location, and build up the stack quickly. Think about what would have been if the variables would have been pushed onto the stack first, and then the literals. Accessing a memory location for the CPU takes up a relatively long time compared to pulling a literal value out of a circuit or CPU register. Since it takes more time to push variables onto the stack vs. literals, the literals would have to wait, then the return address would have to wait, and the local variables would have to wait as well. It's probably not a big concern in efficiency, but that's just my theory for why default arguments are always in the rightmost positions of a function header in C++. It means that the compiler was designed as such.

Google's style guide about input/output parameters as pointers

The Google C++ Style Guide draws a clear distinction (strictly followed by cpplint.py) between input parameters(→ const ref, value) and input-output or output parameters (→ non const pointers) :
Parameters to C/C++ functions are either input to the function, output
from the function, or both. Input parameters are usually values or
const references, while output and input/output parameters will be
non-const pointers.
And further :
In fact it is a very strong convention in Google code that input arguments are values or const references while output arguments are pointers.
But I can't figure out why input/output arguments (I leave output arguments aside) should not be passed by reference. On stackoverflow there are plenty of topics related to this question : e.g. here, the accepted answer clearly say that
it's mostly about style
but that if
you want to be able to pass null, you must use a pointer
So, what's the point to always demand a pointer if I want to avoid the pointer to be null ? Why only use references for input arguments ?
The reason for demanding that output parameters are passed as pointers is simple:
It makes it clear at the call site that the argument is potentially going to be mutated:
foo(x, y); // x and y won't be mutated
bar(x, &y); // y may be mutated
When a code base evolves and undergoes incremental changes that are reviewed by people who may not know the entire context all the time, it is important to be able to understand the context and impact of a change as quickly as possible. So with this style rule, it is immediately clear whether a change introduces a mutation.
The point they are making (which I disagree with) is that say I have some function
void foo(int a, Bar* b);
If the b argument is optional, or it is unnecessary sometimes, you can call the function like so
foo(5, nullptr);
If the function was declared as
void foo(int a, Bar& b);
Then there is no way to not pass in a Bar.
This point (emphasis mine) is completely opinion-based and up to the developer's discretion.
In fact it is a very strong convention in Google code that input arguments are values or const references while output arguments are pointers.
If I intend for b to be an output parameter, either of the following are perfectly valid and reasonable.
void foo(int a, Bar* b); // The version Google suggests
void foo(int a, Bar& b); // Reference version, also perfectly fine.
You're first question: "So, what's the point to always demand a pointer if I want to avoid the pointer to be null?"
Using a pointer announces to the caller that their variable may be modified. If I am calling foo(bar), is bar going to be modified? If I am calling foo(&bar) it's clear that the value of bar may be modified.
There are many examples of functions which take in a null indicating an optional output parameter (off the top of my head time is a good example.)
Your second question: "Why only use references for input arguments?"
Working with a reference parameter is easier than working with a pointer argument.
int foo(const int* input){
int return = *input;
while(*input < 100){
return *= *input;
(*input)++;
}
}
This code rewritten with a reference looks like:
int foo(const int& input){
int return = input;
while(input < 100){
return *= input;
input++;
}
}
You can see that using a const int& input simplifies the code.
They likely use it for consistency because they use output parameters both as references to existing memory (they're modifying previously initialized variables) and as actual outputs (the output arguments are assumed to be assigned by the function itself). For consistency, they use it as a way to more clearly indicate inputs vs. outputs.
If you never need a function/method to assign the memory of the output parameter, like returning a pointer from a lookup or allocating memory itself and returning it through a pointer, use references. If you need to do that but don't care about using pointers to act as an indication of whether a parameter is input or output, use references for output parameters when appropriate. There's no absolute requirement to use pointers in all cases unless the requirements of that function/method itself requires it.

creating functions with default parameters between non-default parameters in C++

My employer company has an API package & I am asked to create a test for QA using a certain function of a class. The function is something like this:
void func(int a, int b, int c, int d, int e);
where b & d are default parameters. The types are obviously not int, I have created them here for understanding purpose. Currently I can use that function by passing NULL for the default args. But I was thinking in the case of above function func, if the default value for b & d was non-zero say 1 & the user did not know this & if he used NULL (which is = 0) then a different result would be arrived.
So I would like to know how should I create such functions that have default args between non-default ones & I should not be needed to pass anything for that arg i.e.
func(23, , 34, , 45);
Currently VS2010 is giving me compile error for similar implementation for our company's API call.
I hope I made the question pretty clear to understand.
I tried searching similar question elsewhere too but could not find solution for my query.
Thank You.
You can't do that, you have to put all non-optional parameters first, followed by optional parameters after.
You can read a bit more about optional parameters here. Microsoft says:
Default arguments are used only in function calls where trailing arguments are omitted — they must be the last argument(s). Therefore, the following code is illegal:
int print( double dvalue = 0.0, int prec );
void func(int a, int c, int e)
{
int default_b = 1;
int default_d = 1;
func(a, default_b, c, default_d, e);
}
Otherwise you simply can't, as there is no named parameters in C++.
(Though another solution would be to use boost::bind or a similar functor).
If you can modify the original function, you can simply use default value at the condition the defaulted parameter are at the end :
void func(int a, int c, int e, int b = 1, int d = 1);
How do you expect the compiler to know that you mean to pass a,c and e and not some other triplet? In a function declaration all parameters after a parameter with default value should have default values. So you can never have default b and d - whenever you pass only three parameters to this function it would mean you want to use the default values for the last 2 parameters and these are d and e. Move your optional parameters as last in the function.
There is no direct way to achieve what you are looking for.
The first alternative would be the use of boost::optional<T> for the parameters.
Another alternative might be named parameters, as implemented in the Boost Parameter Library.
If you think that this might be something for you and you want further elaboration on how these could be used for your use case, let me know and I'll edit this answer.
There is a boost library for this boost::parameter http://www.boost.org/doc/libs/1_53_0/libs/parameter/doc/html/index.html
It supports named parameters in arbitrary order with default values for non used parameters.