Sunday, June 06, 2010

Complaint Against Pass-by-Reference in C++

Since the day I learned about pass-by-reference in C++, I have had this little peeve about it. The following page describes the advantages of passing by reference: http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=166
So here is my plug for pass-by-address. Using * to pass the address of a variable makes it clear that, after the called function returns, its value could be different. However, if passed by reference, just looking at the function call does not make it obvious that the value could be changed. One has to look at the signature of the called function to know that. For example, the following code uses pass by value:

void increment (int n)
{
n++;
}

void myFunc ()
{
int k = 10;
increment (k);
std::cout << k << std::endl; // displays 10
}

If we want increment() to actually change the value of its argument in the calling function, then we can use pass-by-address to pass the address of the int variable. This is the only option available in C.

void increment (int* n)
{
(*n)++;
}

void myFunc ()
{
int k = 10;
increment (&k);
std::cout << k << std::endl; // displays 11
}

Looking at the call to increment() in myFunc(), I can say that the value of k that is printed might not be 10. However, consider the pass-by-reference option added in C++:

void increment (int& n)
{
n++;
}

void myFunc ()
{
int k = 10;
increment (k);
std::cout << k << std::endl; // displays 11
}

This is the same as the pass-by-value code (which prints 10) but with just one '&' character added to the signature of the increment() function. The myFunc() function is unchanged. Reading just the code for myFunc(), I have no clue that k is 11 by the time it is printed. To figure out how this happened, I would have to look up the increment() function signature, which may be in one of the many header files for a library that the application may be using. I think that the syntax could be improved by requiring some character in the increment() call that makes it explicitly clear to the programmer that a reference to the variable is being passed and not a copy. For example, it could be:

increment (@k);

Do you find the C++ pass-by-reference syntax irksome, too? Let me know in the comments section.

2 comments:

Anupam said...

Ajoy,
You raise a valid point about code maintainability.
Can't the problem of not knowing whether to pass by reference or a pointer be fixed by just following a naming convention in the library?
References are useful for code understanding simply because it hides the clutter of pointers in a library. Therefore I like it and probably this was one of the reasons why Java uses references and not pointers.
Maybe C++ should follow Java's lead!

Anupam

Ajoy Bhatia said...

Anupam,

Java "references" are different from C++ references. The behavior of Java references is more like C++ pointers than references, in the strict sense of the word. Java just removed pointer arithmetic, which was a source of many problems in C++. Other than that, it is just the syntax that changed in Java. I would refer you to my previous post for more on this topic: Are Java references pointers?

Also, I am not clear how a naming convention in the library would fix this problem. Would it be a naming convention for the function? A function may have many arguments and the function name cannot indicate which are treated as references and which as copies. Perhaps an example would help.

Thanks for reading...
- Ajoy