Hi,
I was just wondering, is it good to use return without arguments in a void
function as following:
void SetMapLayer()
{
if( !Map ) return;
layer = LAYER_MAP;
}
It works well but it is considered a good programming technic?
TIA, Max.
Jul 22 '05
27 2673
"E. Robert Tisdale" <E.************ **@jpl.nasa.gov > wrote in message
news:3F******** ******@jpl.nasa .gov... Avoid void functions. A function should *always* return a value so that you can use it in an expression.
That's one view. Another is that a procedure with with side effects should
*never* return a value, so that you are not tempted to use it in an
expression and get into trouble with order-of-evaluation ambiguities.
Martijn Lievaart wrote: On Sat, 03 Jan 2004 10:23:14 -0500, Jeff Schwab wrote:
You'll have a hard time tracing exceptions with this design. Why not define a trace object, that prints in constructor and destructor? Much easier to use and works with multiple returns and exceptions. It's what I do if I need this.
So, each time you want to debug a function with multiple return points, you must:
1) Define a class with member references to all of the function's local variables; at least, the ones you want to trace.
No, use one trace class to trace the program flow. When I want to log variables, I use a different (though related) class.
2) Find a cozy place somewhere before any of the function's return points, but after all the traced variables have been defined. IME, this is often impossible. Here is a simplistic case that reflects the common practice of defining some variable, returning if a check succeeds, and otherwise defining some other variables:
template< typename T > void sort_two_object s( T a, T b ) {
TRACE(sort_two_ objects);
bool already_sorted = a < b;
// A Trace object defined here cannot trace the value of copy_of_a, // even if the return statement is not used.
see below
if( already_sorted ) { return; }
// A Trace object defined here will not be destructed if the return // statement is used.
T copy_of_a = a;
LOG("copy_of_a= " << a);
a = b; b = copy_of_a; }
Why do it any other way? Yes multiple exit points can make ad-hoc cerr-debugging harder, but one should not do that anyhow. Writing the TRACE and LOG macros is pretty trivial and make life much easier.
I never was a fan of not allowing multiple exit points, but exceptions embedded it in the language, so I guess we better get used to it. I know I don't have any problem with it.
Exceptions do provide "extra" exit points, but they are not the same as return statements. Exceptions carry information back up the call stack about what went wrong, and why. Often, the information obtained in a high-level catch block is sufficient, and there is no need to look at the lower-level code at all. Even when there is such a need, since my exceptions always include the line number and file number of the correspondi ng throw statement, I know exactly which exit point to watch.
That is true, but I don't see what the problem with multiple exit points is if you're going to rerun the program under the debugger anyhow.
The only real advantage I can see of avoiding multiple exitpoints is that one can put a breakpoint on the common exit. In practice, I don't miss it.
Obviously, multiple exit points, like any language feature can be used and mis-used. I concur that they can introduce problems, but only if mis-used. My personal guideline in this is that the code should read like a story. If not, you have a maintenance problem at least. So this is not really related to multiple exit points, but to obfuscated coding.
I've heard that theory before. The fact is that programs are not stories. When I'm debugging a large piece of code, I have no desire to start at the beginning and proceed to the point of the problem. The time required for such an approcach is linear with the number of lines leading to the point of the problem. By doing instead a binary search for the problem, debug time is significantly reduced. This approach is eased greatly by the absence of spurious return statements. Any extra return statement is what I would call "obfuscated code."
I'm not talking about complete programs being stories, I'm talking about pieces of code, most probably a function. If you do that, the complete program is easy to read and debugging gets much easier. So your argument about binary search is not relevant, that is how one should always debug.
If the program is hard to read, it is hard to debug. If multiple exit points make a function harder to read, they are misused. I still don't see why multiple exit points would be a problem here.
M4
I think we're just not going to agree on this one. I don't care for
your TRACE and LOG macro approach, and I can see that you hate the idea
of giving up the ability to exit a function wherever you see fit. I
congratulate you on having found techniques that work for you, but they
certainly are not appropriate for me. I still recommend avoiding
multiple return points wherever possible, with the exception of... well,
exceptions. :)
-Jeff
Jeff Schwab wrote: It's not just a matter of 'style.' Every extra point of return makes code much harder to debug, since state-validation code to be executed before a function returns must be duplicated for each point of return. Take this advice from someone who has learned the error of his ways: Keep it down to one exit point whenever possible. The only exception to this rule should be the throwing of exceptions.
Some languages, like Tcl, do have great support for techniques relying on multiple points of return. C++ is not such a language.
-Jeff
Not necessarily. There is a style of coding in which the execution
returns out of a function "as soon as possible":
void My_Function(voi d)
{
if (/* first boundary condition fails */)
return;
if (/* next boundary condition fails */)
return;
// ...
return;
}
Although these conditions could be logically ANDed together,
when there are many, it becomes a stylistic or readability nightmare.
The above style reduces the indentation problem of:
void My_Second_Funct ion(void)
{
if (/* first condition is valid */)
{
if (/* second condition is valid */)
{
if (/* third condition is valid */)
{
// etc.
}
}
}
return;
}
And there is the style at my work which uses a boolean
variable for success:
void My_Third_Functi on(void)
{
bool failure(false);
failure = /* first boundary conditional test */;
if (!failure)
{
// execute some code.
failure = /* another test */;
}
if (!failure)
{
// and so on.
}
return;
}
I personally prefer the exit as soon as possible rule,
but this is a religous or style issue.
--
Thomas Matthews
C++ newsgroup welcome message: http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.l earn.c-c++ faq: http://www.raos.demon.uk/acllc-c++/faq.html
Other sites: http://www.josuttis.com -- C++ STL Library book http://www.sgi.com/tech/stl -- Standard Template Library
Thomas Matthews wrote: Jeff Schwab wrote:
It's not just a matter of 'style.' Every extra point of return makes code much harder to debug, since state-validation code to be executed before a function returns must be duplicated for each point of return. Take this advice from someone who has learned the error of his ways: Keep it down to one exit point whenever possible. The only exception to this rule should be the throwing of exceptions.
Some languages, like Tcl, do have great support for techniques relying on multiple points of return. C++ is not such a language.
-Jeff
Not necessarily. There is a style of coding in which the execution returns out of a function "as soon as possible": void My_Function(voi d) { if (/* first boundary condition fails */) return; if (/* next boundary condition fails */) return; // ... return; }
That looks nice from a distance, but I've regretted writing that sort of
code in the past.
Although these conditions could be logically ANDed together, when there are many, it becomes a stylistic or readability nightmare.
Only if done poorly. Code can get a good deal shorter by replacing "if
/*...*/ return" with "and":
void my_function( )
{
if( /* fist condition */
and /* second condition */
and /* third condition */ )
{
// ...
}
}
The above style reduces the indentation problem of: void My_Second_Funct ion(void) { if (/* first condition is valid */) { if (/* second condition is valid */) { if (/* third condition is valid */) { // etc. } } } return; }
If a separate block is needed for each "if" statement, then a function
like this is performing a many different actions, according to the
results of many different tests. Such code often can be improved by
refactoring into several different functions or objects.
And there is the style at my work which uses a boolean variable for success: void My_Third_Functi on(void) { bool failure(false);
failure = /* first boundary conditional test */; if (!failure) { // execute some code. failure = /* another test */; } if (!failure) { // and so on. } return; }
That's heinous.
I personally prefer the exit as soon as possible rule, but this is a religous or style issue.
Yes, apparently so. :)
-Jeff
On Sat, 03 Jan 2004 11:42:15 -0500, Jeff Schwab wrote: I think we're just not going to agree on this one. I don't care for
OK, agree to disagree, but...
your TRACE and LOG macro approach, and I can see that you hate the idea of giving up the ability to exit a function wherever you see fit. I congratulate you on having found techniques that work for you, but they certainly are not appropriate for me. I still recommend avoiding
Why are the they not apropriate for you? The TRACE macro is much easier
than manually adding print statements and less errorprone.
M4
Martijn Lievaart wrote: On Sat, 03 Jan 2004 11:42:15 -0500, Jeff Schwab wrote:
I think we're just not going to agree on this one. I don't care for
OK, agree to disagree, but...
your TRACE and LOG macro approach, and I can see that you hate the idea of giving up the ability to exit a function wherever you see fit. I congratulat e you on having found techniques that work for you, but they certainly are not appropriate for me. I still recommend avoiding
Why are the they not apropriate for you? The TRACE macro is much easier than manually adding print statements and less errorprone.
M4
In your opinion. Certainly not in mine.
Andrew Koenig wrote: E. Robert Tisdale wrote:
Avoid void functions. A function should *always* return a value so that you can use it in an expression.
That's one view. Another is that a procedure with with side effects should *never* return a value so that you are not tempted to use it in an expression and get into trouble with order-of-evaluation ambiguities.
Avoid [writing] functions with side effects.
Avoid [writing] functions that modify global variables.
Pass by value, const reference or const pointer.
Don't implement this:
void foo(myClass& myObject);
Implement this:
myClass foo(void);
instead so that you can write:
const myClass x = foo();
instead of:
myClass x;
foo(x);
Programs which modify state variables (state machines)
are notoriously difficult to analyze and maintain.
The state determines the flow of execution
which, in turn, determines state
which, in turn, etc.
What you end up with is "spaghetti code".
(If you trace the thread of execution through the code
with a pencil, the trace resembles a plate of spaghetti.)
Structured programming helps but
the C++ computer programming language includes features
(i.e. functions can return objects of any type by value)
that allow programmers to write programs
that are virtually *stateless*.
The C++ programmer simply writes functions
which return the value of expressions
containing lower level functions.
Once the lower level functions have been tested and proven correct,
it is usually a simple matter to prove that the function
which uses them is correct. This is sometimes called
functional programming or, more generally, applicative programming.
I believe that the reason these features were included
in the C++ computer programming language
was to encourage good programming practice and I try to use them.
Your approach appears to me to be more "ad hoc".
Your rationale doesn't appear to be rooted in good computer science
but in anecdotes from personal experience using the language.
Do you have a coherent strategy that you use to write C++ programs
that other C++ programmers can read, understand and maintain?
If so, how is it different from the "strategy" employed
by the spaghetti coders of yesterday and today?
"E. Robert Tisdale" <E.************ **@jpl.nasa.gov > wrote in message
news:3F******** ******@jpl.nasa .gov... Andrew Koenig wrote:
E. Robert Tisdale wrote:
Avoid void functions. A function should *always* return a value so that you can use it in an expression. That's one view. Another is that a procedure with with side effects should *never* return a value so that you are not tempted to use it in an expression and get into trouble with order-of-evaluation ambiguities.
Avoid [writing] functions with side effects. Avoid [writing] functions that modify global variables.
Better yet, avoid global variables. If there *are* global variables, and
they need to be modified, It would be hard to avoid doing so in a function
though, eh...?
Pass by value, const reference or const pointer.
Don't implement this:
void foo(myClass& myObject);
Implement this:
myClass foo(void);
instead so that you can write:
const myClass x = foo();
instead of:
myClass x; foo(x);
Fine, if all you want to do with x if foo. But most times you have to keep
objects around for a while. So how would your pass-by-reference and
never-have-void-functions rules handle the problem of using an object more
than just that once? I've got all kinds of objects that have to stay around
for a while: my dsp object, my application object, my effect object, my
editor object, my settings object, etc. Any one of these might have to
interact with another of these due to a change from just about any source:
the host program, the user, the hardware, a timer, etc. Personally, in the
above example, I'd write:
myClass x;
x.foo();
(Assuming that the primary purpose of foo was to manipulate x, of course.) Programs which modify state variables (state machines) are notoriously difficult to analyze and maintain. The state determines the flow of execution which, in turn, determines state which, in turn, etc. What you end up with is "spaghetti code". (If you trace the thread of execution through the code with a pencil, the trace resembles a plate of spaghetti.)
All programs are state machines, really. You can hide the state information
behind your wall of nested function calls and constructors, but your program
is still a state machine. And being a state machine does not make it
"spaghetti code". What makes it spaghetti code is lack of logical design.
Structured programming helps but the C++ computer programming language includes features (i.e. functions can return objects of any type by value) that allow programmers to write programs that are virtually *stateless*. The C++ programmer simply writes functions which return the value of expressions containing lower level functions. Once the lower level functions have been tested and proven correct, it is usually a simple matter to prove that the function which uses them is correct. This is sometimes called functional programming or, more generally, applicative programming.
Nice idea, (also called "black box" programming, correct?) but not always
possible in practice. There are often complex interactions between objects
whose only relation to each other is through the object that is using them,
and it is that interaction that introduces the complexity. The lower-level
objects cannot be held responsible for the state of other low-level objects.
Only the higher-level object can do it, and to do so often requires changes
to the low-level object designs that was not thought of when writing them
and "proving" their correctness. I believe that the reason these features were included in the C++ computer programming language was to encourage good programming practice and I try to use them.
Me, too. It's just not always possible. Occasionally, despite myself, I
find myself writing multiple return statements in one function, simply
because it is the most straight-forward way to accomplish the task.
(Especially in the real-time environments I work in now, where speed is
essential.)
Your approach appears to me to be more "ad hoc". Your rationale doesn't appear to be rooted in good computer science but in anecdotes from personal experience using the language. Do you have a coherent strategy that you use to write C++ programs that other C++ programmers can read, understand and maintain? If so, how is it different from the "strategy" employed by the spaghetti coders of yesterday and today?
Hey, who wants "other C++ programmers" to maintain our code? We need the
job security of total code obfuscation! :-)
-Howard This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics |
by: REH |
last post by:
The other day I did something like this:
void foo
{
}
void bar()
{
return foo();
}
|
by: G Patel |
last post by:
Hi,
If I want to call functions that don't return int without declaring
them, will there be any harm?
I only want to assign the function(return value) to the type that it
returns, so I don't see how the return value comes to play here.
Ex
|
by: Greenhorn |
last post by:
Hi,
when a function doesn't specify a return type ,value what value is
returned. In the below programme, the function sample()is returning the
value passed to 'k'.
sample(int);
main()
{
int i = 0,j;
j = sample(0);
|
by: zeroDontSpamtype |
last post by:
Hi,
Why do strcpy and strcat (and strupr and strlwr in some nonstandard
implementations) return a char*? Surely the logical (and DMA-safe)
)return type for these would have been void??
Thanks,
James McLaughlin.
|
by: geoffblanduk_nospam |
last post by:
Just curious, we no longer require void on a method that takes no
parameters;
void methodWithNoParameters(void) has been replaced by void
methodWithNoParameters().
Is there a good reason we still have to specify void for a method that
returns no result? For example;
private void methodWithNoReturn() could been replaced by private
| |
by: skishorev |
last post by:
Hi,
Here I am taking two functions. void f(int,int) and another one is
float f(int,int).
Is it possible to overload with return values.
Thx,
kishore
|
by: msolem |
last post by:
I have some code where there are a set of functions that return
pointers to each other. I'm having a bit of a hard time figuring out
the correct type to use to do that.
The code below works but I'm defining the functions as void*, and then
casting when I use them. This code is going into a general purpose
framework, and it would be much nicer if the user didn't need to do
any casting.
Can someone tell me how to set up those typedefs...
|
by: noridotjabi |
last post by:
What is the purpose of the function pointer? Why do you need a pointer
to a function. I cannot really think of any application where this is
the only or even easiest solution to a problem. I'm sure there are
really good aplications for it I just cannot think of any, so if anyone
can tell me why a pointer to a function is nessisary and when it
can/should be used I would apreciate that. Thanks.
Nori
|
by: Pedro Pinto |
last post by:
Hi there once more........
Instead of showing all the code my problem is simple.
I've tried to create this function:
char temp(char *string){
alterString(string);
return string;
|
by: marktang |
last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look !
Part I. Meaning of...
|
by: Hystou |
last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it.
First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
| |
by: jinu1996 |
last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth.
The Art of Business Website Design
Your website is...
|
by: Hystou |
last post by:
Overview:
Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
|
by: tracyyun |
last post by:
Dear forum friends,
With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
|
by: agi2029 |
last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own....
Now, this would greatly impact the work of software developers. The idea...
|
by: conductexam |
last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one.
At the time of converting from word file to html my equations which are in the word document file was convert into image.
Globals.ThisAddIn.Application.ActiveDocument.Select();...
|
by: adsilva |
last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
| |
by: muto222 |
last post by:
How can i add a mobile payment intergratation into php mysql website.
| |