views:

179

answers:

5

Well, here we are. Yet another proposed practice that my C++ book has an opinion on. It says "a returning-value(non-void) function should not take reference types as a parameter." So basically if you were to implement a function like this:

int read_file(int& into){
   ...
}

and used the integer return value as some sort of error indicator (ignoring the fact that we have exceptions) then that function would be poorly written and it should actually be like

void read_file(int& into, int& error){

}

Now to me, the first one is much clearer and nice to use. If you want to ignore the error value, you do so with ease. But this book suggests the later. Note that this book does not say returning value functions are bad. It rather says that you should either only return a value or you should only use references.

What are your thoughts on this? Is my book full of crap? (again)

+9  A: 

The advice is silly. A direct return value is much smaller and easier to type.

Direct return:

if (read_file(...)) {
    ... handle problem ...
}

Indirect return:

int status;

read_file(..., status);
if (status) {
    ... handle problem ...
}

Edit: a bigger issue is whether to use non-const reference parameters at all. It can be surprising to have side effects come flying out of the parameters. One coding standard says that reference parameters should be const and output parameters should use pointers. That way the reader gets a & at the point of call that shouts out "something happens to this parameter".

Daniel Newby
About the non-const bit, yea I've pondered on this quite a bit. I write in C a lot more than C++ so I usually do pointers instead of references..
Earlz
I don't agree with that coding standard you cite. Before you use a function you should read and understand the signature, not just glance at the call site and make assumptions.
Brian Neal
@Brian Neal: That's the point. Code can be, and should aspire to be, fairly understandable just by reading the call site. By clearly identifying the (usually) rare output parameters, you relieve the reader of the burden of being forced to constantly refer to signatures. (Which they will do a bad job of anyway, producing avoidable bugs.)
Daniel Newby
I think in C++ you need to understand the function by first reading the signature and any comments in the header file, and not rely on the call site. After all, references were invented because they solved problems pointers could not. You simply can't make all out-parameters pointers all the time.
Brian Neal
Actually, iirc, references were created as a shortcut for pointers - anything you can do with references, you can do with pointers, sans the const portion, which is not being stated by your comment there.
aperkins
@aperkins - references were created largely to support operator overloading. Pointers come with baggage because they can be null. If I want to tell the caller that he can't pass in null, I will use a reference. Therefore the coding standards that say "all out or in-out parameters must be pointers" don't seem to add value to me. Just my opinion.
Brian Neal
@Brian Neal : I agree with this, although I would point out that most standards are there to be just that - a standard. They can be broken, but you should have a good reason to do so. I have often found that if I question WHY I am breaking a "best practice", usually (although not always) I will find a better solution, or will find I am thinking about a problem wrong. If that is not the case, then break the best practice, but be sure to document it :)
aperkins
@aperkins Sure, but like I said, I don't consider that a best practice. I haven't seen that practiced much in the wild, or for that matter in the STL or other commonly used libraries.
Brian Neal
+4  A: 

I think it's more important to be consistent across a project than to evangelize one way as better than another.

Paul Ellis
+1 - The worst problems with exceptions come from mixing code that uses them with code that isn't aware of them. Same with this, if you're used to the second style in a code base, it'll be easy to accidentally ignore an error returned by a lone function using the first style. If you're used to the first style, a lone function using the second style will stand out as awkward. Win32, the standard library and POSIX generally use the first style, so that might be an influencing factor in your decision.
Eclipse
+2  A: 

It's a rather uninteresting and subjective style debate. Personally I'd rather return a std::pair, a struct, or (in TR1) a tuple.

Brian Neal
+1  A: 

They are attempting to teach you the practice of "if you return a value, do not modify the variables in the call parameters"

Instead, you can do something like the following:

int read_file(const int& into){ ... }

My syntax might be slightly off, but the const tells it you cannot change it inside the method, but you still get the pass by reference, which is nice with objects. With the int, it doesn't really buy you anything.


Edit: Additionally, as others have noted, if your goal is to have multiple return values, then it is usually a better idea to either do as the book suggests, or to instead create a "composite" return type - use a pair, your own custom type, etc.

aperkins
A: 
//somewhere deep in the code space
a = func(i); //i is modified inside func() or not?    
j = i; //what is this for? depends on the answer to the first question

If the code was written with respect to the rule that the book suggests, you can be sure that "i" is not modified just by looking at the call site, thus the code says more to you than otherwise

Anyway, I would prefer to return a tuple, not modifying by reference

Alsk
Yea, non-const references are evil in my opinion.
Earlz