Sign in to follow this  

Never return void?

This topic is 2656 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I had a brief conversation with a colleague who stated, 'a method should never return void'. I rejected the idea out of hand, and we didn't have time to discuss it. So I was wondering if anyone here has heard of this idea or knows why this would be desirable. I have to confess I have no idea why this would be a good idea.

Just to be clear I don't mean explicitly trying to return a void or void* or something, but having a void return type on a method signature.

Share this post


Link to post
Share on other sites
well if you mean

void SetX(int x); like that

i dont know why that would be bad unless you want to return a value to check if the function exectued proper


but if you ment

void SetSelected(int mousex, int mousey)
{
for(int i = 0... iteration lol )
{
if(the condition is met)
{
m_selected = i;
return;
}
}
}

then idk y that would be bad.. or if somthing happened that you dident want to happen.. sorry thats not much info but i thought i would give it a shot

Share this post


Link to post
Share on other sites
Some functions simply have no output, period.

That said, for some Set methods, it's sometimes pertinent to return a reference to the object so you can use cascading calls like this:
Rect.SetLeft( 0 ).SetRight( 320 );

Share this post


Link to post
Share on other sites
It's the same nosense as saying that "a method should only have one return point" and that assholes people who think that know everything will rub on your face as undenyable truth and look at you like meaning "you're ignorant".

Shame on them.

Share this post


Link to post
Share on other sites
Sometimes this attitude goes hand-in-hand with an avoidance toward structured exception handling -- In the absence of exceptions, return values are really the only way to communicate that something has gone wrong in the function, and so it is reasonable to then assume that any function that can fail needs some kind of return value. Of course, using this kind of error-code return value may then necessitate the use of out-params if the return value and error code cannot be reconciled into the same return type.

Another, poorer argument is that no return value tends to imply that state is modified in some other way, which can certainly be abused. I say this is a poorer argument as the real problem is the abuse of state, and having a return value doesn't actually fix the problem unless you use it as a means to fix the other problem.

Your colleague may also come from a more functionally-minded (in the way of, say, Haskell or another functional programming language, not C-style 'functions', which are, more accurately, procedures.) background, and they perhaps tend to think in this way.

In general, its probably true that a tendency toward actual return values is a good thing, but I wouldn't go out of my way to avoid 'void' if it were the natural way to express the behavior. I prefer SEH to handle and communicate exceptional cases myself, but there are places which discourage or outlaw exceptions in their C++ code -- Google, for example, forbids exception handling in their C++ coding standard, its often forbidden in the embedded world (what little part of it that has embraced even some C++), and EA has their "EASTL" which provides STL-like functionality aimed at gaming applications and which also avoids exception handling -- as a side note, you can actually compile most STL implementations without exception handling.

Share this post


Link to post
Share on other sites
Quote:
Original post by Bearhugger
Some functions simply have no output, period.

That said, for some Set methods, it's sometimes pertinent to return a reference to the object so you can use cascading calls like this:*** Source Snippet Removed ***


It may be semantics, but actually all functions, in the pure sense, return at least one value, take at least one parameter, has no side-effects, accesses no global data and calls only other pure function. If any one of these requirements is not satisfied, then you're really talking about a procedure, or subroutine.

Making the distinction is actually very important these days, as pure functions can be made parallel trivially, which is a hot topic for optimization in today's multi-core, distributed and parallel-processing world (SIMD, CUDA, OpenCL, etc).

EDIT: Another feature of "pure" functions is that they are inherently testable due to the fact that all paths into and out of the function are known. If you know the function works for all input values and produces only expected outputs, then that function is secure, and other secure functions may call it also and retain their security. Actually, I kind of wish C and C++ would adopt some sort of "pure" keyword so the compiler could prevent you from doing unpure things in functions you intend to be pure.

[Edited by - Ravyne on August 31, 2010 9:03:10 PM]

Share this post


Link to post
Share on other sites
It's a strictly C thing.

As per:
Quote:
The type-specifier can specify any fundamental, structure, or union type. If you do not include type-specifier, the return type int is assumed.


While likely a perfectly valid concept, following the principle of least surprise, use a type.

Share this post


Link to post
Share on other sites
Antheus -- But the OP is saying that the return type on the method signature is given explicitly as 'void'. Your source lists 'void' as a valid type specifier, so I'm confused on what point you are trying to make. Explain?

Share this post


Link to post
Share on other sites
I've heard this argument made a little. It's done by people who favor a bit more idealistic view of things. They tend to be functional programmers who're for some reason or another stuck in a not functional language. The basic concept is that functions should do things. A function that returns void doesn't do anything (and doesn't line up with the mathematical concept of a function), it just sucks in parameters and does some weird side effect that isn't elegant, or testable, or nice (in their view). And if you're coming from a world where side-effects are offensive to the extreme... it kinda sorta makes sense.

Though that is (imo) a bit impractical.

Share this post


Link to post
Share on other sites
Quote:
Original post by Ravyne
Antheus -- But the OP is saying that the return type on the method signature is given explicitly as 'void'. Your source lists 'void' as a valid type specifier, so I'm confused on what point you are trying to make. Explain?


If you don't specify a type, int is automatically selected by compiler.

foo(int x) {
printf("%d", x);
}
// is same as
int foo(int x) {
printf("%d", x);
}


This is the best I can interpret the original "having a void return type on a method signature."

Share this post


Link to post
Share on other sites
Antheus, right, that part I am in agreement with, however, the OP specifically said that 'void' is in the method signature and, again, the source you linked explicitly includes 'void' as a valid type specifier.

We are not talking about:

foo(int x) {
printf("%d", x);
}

but about:

void foo(int x) {
printf("%d", x);
}

Unless my "vanilla" C is rusty, and the latter is not valid C for other reasons (or has the effect that "void" simply disappears), I still fail to see what point you are trying to make.

Share this post


Link to post
Share on other sites
Quote:
Original post by Ravyne
void foo(int x) {
printf("%d", x);
}

Unless my "vanilla" C is rusty, and the latter is not valid C for other reasons (or has the effect that "void" simply disappears), I still fail to see what point you are trying to make.

Well, if we're talking "vanilla" C, why not do it the good ol' fashion way (not required anymore in C99)...
void f(x) int x; {
printf("%d", x);
}

Share this post


Link to post
Share on other sites
My guess about jjd's colleague would be that they believe in functions no having side-effects (not anything to do with syntax). A void function is almost guaranteed to have side effects (assuming none of the arguments are 'outputs'), so it's the antithesis of side-effect-free design.

Basically what Ravyne was saying about pure functions.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
Just wanted to say that IMO Ravyne has officially rocked this thread, saying everything I wanted to say, at least as well.


Heh, Accolades from a mod on high! Color me flattered [grin]

Quote:
Original post by Washu
Quote:
Original post by Ravyne
void foo(int x) {
printf("%d", x);
}

Unless my "vanilla" C is rusty, and the latter is not valid C for other reasons (or has the effect that "void" simply disappears), I still fail to see what point you are trying to make.

Well, if we're talking "vanilla" C, why not do it the good ol' fashion way (not required anymore in C99)...
void f(x) int x; {
printf("%d", x);
}


I actually kind of like that syntax, just because it encourages easy commenting of parameters:
void f(x, y)
int x; // some comments about x
int y; // some comments about y
{
// do some stuff with x and y
}

I had toyed around with designing a language syntax once which had similar, but slightly less redundant syntax. Something like:
function f takes
x as int, // some comments about x
y as int // some comments about y
returns
int
begin
// do some stuff with x and y
end

Share this post


Link to post
Share on other sites
Thanks everyone for helping me to understand this better. My colleague does come from a functional background and so it may be this that is informing his opinion.

I should have been clearer in my description, so my use of the word function may have been wrong. In particular, this is the situation


class foo
{
public:
void setBar(int);
};



So I am talking about a setter/mutator on an object. There is no real distinction made between function and subroutines in C/C++ AFAIK. Clearly this is never going to be a 'pure' function because it is intended to change state. As mentioned by Bearhugger, you could return a reference to the object to chain together function calls, but I have confess that doesn't make me feel comfortable and I'm not sure why. There is probably a place for it, but I wouldn't like to use it by default.

@Ravyne Interestingly a lot of what you have mentioned (pure functions and your desired function syntax) are pretty much what you find in fortran95.

Share this post


Link to post
Share on other sites
I guess the OP's buddy is more knowledgeable than the C++ design committee. C++ is full of void functions.

http://www.cplusplus.com/reference/stl/vector/push_back/

http://www.cplusplus.com/reference/stl/list/pop_back/

http://www.cplusplus.com/reference/stl/map/clear/

http://www.cplusplus.com/reference/stl/queue/pop/

Share this post


Link to post
Share on other sites
Quote:
Original post by jjd
... As mentioned by Bearhugger, you could return a reference to the object to chain together function calls, but I have confess that doesn't make me feel comfortable and I'm not sure why. There is probably a place for it, but I wouldn't like to use it by default.


Its probably a good thing that this makes you feel uneasy. It is a not-entirely uncommon trick, and it does have its uses -- certainly the syntax can be quite convenient. I worry though, if most compilers are able to optimize out the fact that different references are being returned and modified, even though they refer to the same object. I'd imagine they might, since its essentially the same thing returning a reference to chain operators like += (actually, if you wrote it using "operator +=" syntax, it would look just like cascading, so I bet most compilers will do that optimization.)

Syntactically its a mixed bag... I find that returning a reference to the base object sometimes allows you to chain entirely unrelated things, like "foo.set_color(color).do_dishes()" or something, which makes the code less readable, IMHO. It's better if the set_color method could return some type that only allowed other color/drawing commands to cascade from it, although in practice this means introducing types that are sometimes redundant.

One place I've used the cascading syntax to great effect recently was in a parser I wrote for a small predicate language. It consisted of binary expressions (==, !=, <, >=, etc) expressed as methods and boolean operators (and, or, not). There were factory methods to construct the expressions, which could not be chained directly -- but on each expression there were And(expr) and Or(expr) methods which would yield a new expression consisting of the invoking expression and the parameterized expression, and this composite expression could, of course, be And'ed or Or'ed again in the same way. Not(expr) was a little different since it's a unary operation, so it was a free-standing function returning an expression. This allowed me to write code like "pred p = foo.GreaterThan(bar).And(baz.BeginsWith("Hello World!")" of course, that's just for testing things out, normally this type of cascading would be generated by the parser, so you're passing around the expression that's been built thus far, and each new keyword encountered by the parser "cascades" the correct operator.

Quote:
Interestingly a lot of what you have mentioned (pure functions and your desired function syntax) are pretty much what you find in fortran95.


I've never taken more than a very cursory glance at Fortran in any flavor, and don't have a strong association in my mind between it and functional programming, but that doesn't actually surprise me given its long-time favor in scientific fields, and the fact that it is known to be quite favorable to optimization -- but hey, I guess I've learned something new today.

Share this post


Link to post
Share on other sites
Quote:
Original post by Ravyne
I actually kind of like that syntax, just because it encourages easy commenting of parameters:


I think it's incredibly ugly, and honestly don't understand how it ended up coming first before the modern style (not required in C89 either AFAIK; it's just the difference between K&R and ANSI). How is it even easier to parse, let alone easier to work with?

You can, of course, still comment parameters the same way in modern style:

void f(
int x, // some comments about x
int y // some comments about y
) {
// do some stuff with x and y
}





To the OP: Sure, a mutator normally has no reason to return a value. But do you have a reason to write a mutator? :)

Share this post


Link to post
Share on other sites
I imagine if you're coming from a style where exceptions aren't used, every function should return an error code because if you don't do it up-front and you go to add one later it will be more maintenance work finding all the references and correctly propagating the new errors up. It stabilises the client interface I guess, particularly important in places like a library where you might not have access to all the calling code.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
Quote:
Original post by Ravyne
I actually kind of like that syntax, just because it encourages easy commenting of parameters:


I think it's incredibly ugly, and honestly don't understand how it ended up coming first before the modern style (not required in C89 either AFAIK; it's just the difference between K&R and ANSI). How is it even easier to parse, let alone easier to work with?

You can, of course, still comment parameters the same way in modern style:

void f(
int x, // some comments about x
int y // some comments about y
) {
// do some stuff with x and y
}


See, I actually find this syntax uglier than the former, despite its redundancy. There's just something icky about having a line that reads only ') {'. Yuck!

I suppose some straight-forward macros could essentially make my syntax a reality, but that's quite abusive of macros and not really worth it of course. The idea of the syntax I was designing back then was that the code was really meant to be self-documenting, and read in a very natural english (thought, of course, hadn't really been given to other human languages).

Today I'm not so much enamored with that particular idea, and my current flight of fancy/Toy language is more mathematical/functional in design (Scala is probably most similar), strong, inferred typing, functions/procedures which are templates by default, and with prototype-based inheritance. At some point I think all wannabe language designers reach a point where they aren't just putting new words on a mashup of their two favorite languages and start looking towards designs that are novel in less superficial ways [grin]

Share this post


Link to post
Share on other sites
Playing devil's advocate here:
One argument for non-void return types is that returning the this pointer can be useful for method chaining, such as in the named parameter idiom, or assignment operators and the << and >> operators for serialisation / deserialisation etc.

One thing's for sure though: "Never say never", and "there's an exception to every rule" (though in this case I would argue that there isn't such a rule).

Share this post


Link to post
Share on other sites
Inflammatory over-generalization*: if your colleague's argument is that functions shouldn't have side-effects, then he's using the wrong language; if his argument is anything else, then he's wrong. Returning a value when there is no meaningful value to return is counterproductive and confusing. Not all functions have any meaningful error condition.

* Disclaimer: strong wording used only for effect. There are always exceptions to everything.

Share this post


Link to post
Share on other sites
about the actual RETURNING void, i've heard some arguments stating one should not have returns in a function, and just flow trough to the end.

so instead of

void func()
{
if(!something)
return;
if(!somethingelse)
return;
do something;
}

one should have

void func()
{
if(something)
{
if(somethingelse)
do something;
}
}


and there i do agree. if it gets too nested, i create new functions.

other than that, void functions are great, i use them very often.

Share this post


Link to post
Share on other sites

This topic is 2656 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this