Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optional function parameters: Use default arguments (NULL) or overload the function?

I have a function that processes a given vector, but may also create such a vector itself if it is not given.

I see two design choices for such a case, where a function parameter is optional:

Make it a pointer and make it NULL by default:

void foo(int i, std::vector<int>* optional = NULL) {   if(optional == NULL){     optional = new std::vector<int>();     // fill vector with data   }   // process vector } 

Or have two functions with an overloaded name, one of which leaves out the argument:

void foo(int i) {    std::vector<int> vec;    // fill vec with data    foo(i, vec); }  void foo(int i, const std::vector<int>& optional) {   // process vector } 

Are there reasons to prefer one solution over the other?

I slightly prefer the second one because I can make the vector a const reference, since it is, when provided, only read, not written. Also, the interface looks cleaner (isn't NULL just a hack?). And the performance difference resulting from the indirect function call is probably optimized away.

Yet, I often see the first solution in code. Are there compelling reasons to prefer it, apart from programmer laziness?

like image 555
Frank Avatar asked Mar 31 '09 23:03

Frank


People also ask

Can we overload function with default arguments?

No you cannot overload functions on basis of value of the argument being passed, So overloading on the basis of value of default argument is not allowed either. You can only overload functions only on the basis of: Type of arguments. Number of arguments.

How do you pass an optional parameter to a function?

To declare optional function parameters in JavaScript, there are two approaches: Using the Logical OR operator ('||'): In this approach, the optional parameter is Logically ORed with the default value within the body of the function. Note: The optional parameters should always come at the end on the parameter list.

What is an optional parameter in a function?

What are Optional Parameters? By definition, an Optional Parameter is a handy feature that enables programmers to pass less number of parameters to a function and assign a default value.

What are default and optional parameters?

By default, all parameters of a method are required. A method that contains optional parameters does not force to pass arguments at calling time. It means we call method without passing the arguments. The optional parameter contains a default value in function definition.


1 Answers

I would not use either approach.

In this context, the purpose of foo() seems to be to process a vector. That is, foo()'s job is to process the vector.

But in the second version of foo(), it is implicitly given a second job: to create the vector. The semantics between foo() version 1 and foo() version 2 are not the same.

Instead of doing this, I would consider having just one foo() function to process a vector, and another function which creates the vector, if you need such a thing.

For example:

void foo(int i, const std::vector<int>& optional) {   // process vector }  std::vector<int>* makeVector() {    return new std::vector<int>; } 

Obviously these functions are trivial, and if all makeVector() needs to do to get it's job done is literally just call new, then there may be no point in having the makeVector() function. But I'm sure that in your actual situation these functions do much more than what is being shown here, and my code above illustrates a fundamental approach to semantic design: give one function one job to do.

The design I have above for the foo() function also illustrates another fundamental approach that I personally use in my code when it comes to designing interfaces -- which includes function signatures, classes, etc. That is this: I believe that a good interface is 1) easy and intuitive to use correctly, and 2) difficult or impossible to use incorrectly . In the case of the foo() function we are implictly saying that, with my design, the vector is required to already exist and be 'ready'. By designing foo() to take a reference instead of a pointer, it is both intuitive that the caller must already have a vector, and they are going to have a hard time passing in something that isn't a ready-to-go vector.

like image 99
John Dibling Avatar answered Oct 06 '22 18:10

John Dibling