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.
🔒 Locked
Never return void?
Advertisement
Original Post
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.
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.
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
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
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:
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 );
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.
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.
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]
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.
Though that is (imo) a bit impractical.
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 asint foo(int x) { printf("%d", x);}This is the best I can interpret the original "having a void return type on a method signature."
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.
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.
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);}
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.
Basically what Ravyne was saying about pure functions.
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 yreturns intbegin // do some stuff with x and yend
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
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.
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.
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/
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/
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.
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? :)
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement