Hello,
i have a question about "design" issues in C.
In ACMqueue of february
(article here: http://www.acmqueue.org/modules.php?...owpage&pid=364
), KV says:
A dangerous if clause is one in which the code you want to protect
with the if isn't really protected. Consider the following pseudocode:
0: if (out < 0)
1: return (fileError)
2:
3: if (permission < operator)
4: return (permissionErro r)
5:
6: if (data.len() <= 0)
7: return (dataError)
8:
9: write(out, data, data.len)
(...)
The reason that all the if statements were added was to protect
the program from calling the write() function when there was
a problem, so the code should be structured in just that way:
0: if ((out >= 0) && (permission >= operator) && (data.len() 0))
1: write(out, data, data.len)
2: // Put all the error condition returns here.
In my mind, man can argue with the latter code, man has to copy the error
checks
and have twice the same code. What do you thinks about this code snippet?
Thanks for your replies,
rogz
Oct 30 '06
27 5388
Ancient_Hacker wrote:
rogz wrote:
>>0: if (out < 0) 1: return (fileError) 2: 3: if (permission < operator) 4: return (permissionErro r) 5: 6: if (data.len() <= 0) 7: return (dataError) 8: 9: write(out, data, data.len)
There are several disparate issues with this code and the original
writer wasnt very good at pointing them out. Here's my view:
(1) Some people think a function should have just ONE clear exit
point, at the bottom. I realize that can get a bit long-winded, but it
can make the code MUCH CLEARER, much easier to set breakpoits, much
easier to add code you're SURE will get run every time. Multiple entry
points went out with FORTRAN II, why do we still have multiple exit
points in this 21sh century?
This is certainly a common opinion, but the code I maintain embraced the
other approach: if you have special cases while setting up the main meat
of the function that suggest that continuing makes no sense, then bail
out early.
We have a whole runtime-enabled logger system so, as long as you log the
entry and exit, debugging is easy and the code is easy to read.
Once we get into the main logic for the function we usually have the
usual assortment of breaks to ensure that there is only one more exit
point to be had.
The other approach I've seen is to have all the special cases handled by
a number of "goto early" or "goto error", where the return is normalized
and control short-circuited to the exit point.
All of these approaches make sense under the right circumstances, but
this maintenance drone prefers code that can be easily read,
top-to-bottom, to figure out what it is *supposed* to do so the bugs are
easier to find.
Freeing up my cognitive energy by being able to discard early control
paths as I go really helps me solve some obscure problems. It also
allows one to say with accuracy that some variable or parameter is in
some known range (e.g., some value is or is not null, or some parameter
cannot possibly be 0, &etc.) after some specific point.
I'm speaking as someone who might not be able to run a debugger on live
code (I maintain chunks that are compiled with older compilers that have
crufty debuggers that don't run on later releases of Windows, for example).
On 30 Oct 2006 06:17:28 -0800, "Ancient_Hacker " <gr**@comcast.n et>
wrote:
>(1) Some people think a function should have just ONE clear exit point, at the bottom. I realize that can get a bit long-winded, but it can make the code MUCH CLEARER, much easier to set breakpoits, much easier to add code you're SURE will get run every time. Multiple entry points went out with FORTRAN II, why do we still have multiple exit points in this 21sh century?
Because in some circumstances, it makes the code much clearer, much
easier to set breakpoints, and much easier to add code to individual
tests.
IOW, "some people" are not always right. In the example given, I would
prefer the form presented as a bad example :-)
BTW, what do multiple entry points have to do with multiple exit
points?
--
Al Balmer
Sun City, AZ
Michal Nazarewicz wrote:
>>>0: if (out < 0) 1: return (fileError) 2: 3: if (permission < operator) 4: return (permissionErro r) 5: 6: if (data.len() <= 0) 7: return (dataError) 8: 9: write(out, data, data.len)
Makes me feel uncomfortable
>
"Ancient_Hacker " <gr**@comcast.n etwrites:
>(1) Some people think a function should have just ONE clear exit point, at the bottom. I realize that can get a bit long-winded, but it can make the code MUCH CLEARER,
I agree totally, especially when maintaining code that has grown to a
hundred lines per function.
>
Or much less clear when it comes into nesting ifs which, IMO, is less
readable then returning when error condition occurs.
which is why I prefer "exceptions first with else if" or goto error exit
>
>much easier to set breakpoits, much easier to add code you're SURE will get run every time. Multiple entry points went out with FORTRAN II, why do we still have multiple exit points in this 21sh century?
I believe, I've heard about some research showing that programmers
tend to make less errors when they are allowed to use 'break' - maybe
the same goes to multiple exit points.
>Now to get just one exit point TAKES A LITTLE MORE WORK and a little more nesting or use of "break".
Isn't "break" really cheating? Like in:
#v+
answer;
do {
some stuff;
if (error 1) {
answer = error1;
break;
}
some stuff();
if (error 2) {
answer = error2;
break;
}
some stuff;
if (error 1) {
answer = error2;
break;
}
some stuff;
answer = success;
} while (0);
return answer;
#v-
I would say yes, since it can easily be handled with a reasonable amount of
indenting (and if it can't then it's time to consider two smaller
functions)
>
It looks just like the same function with many exit points but
uglier.
Just showing my point of view though.
>Personally I'm a nervous nelly and won't use "break" (see ATT $400 million looss due to the vagaries of "break"). So I end up with code like the stuff below. Your opinion may vary. :
ErrorType Answer; if( out >= 0 ) { if( permission >= operator ) { if( data.len 0 ) { Answer = write( ....) 0; } else Answer = BADLEN; } else Answer = BADPERMS; } else Answer = BADOUT
return Answer;
For that depth that would satisfy me
>
Why not:
#v+
ErrorType Answer;
if (out<0) {
Answer = BADOUT
} else if (permission<ope rator) {
Answer = BADPERMS;
} else if (data.len<=0) {
Answer = BADLEN;
} else {
Answer = write(...) 0;
}
return Answer;
#v-
although I prefer that
>
And then, of course, since I prefer data-oriented to process-oriented, there
is
Answer = out < 0 ? BADOUT :
permission < operator ? BADPERMS :
data.len() <= 0 ? BADLEN :
write(...) <= 0 ? BADWRITE :
SUCCESS;
--
Bill Medland
Ancient_Hacker wrote:
>
(1) Some people think a function should have just ONE clear exit
point, at the bottom. I realize that can get a bit long-winded, but it
can make the code MUCH CLEARER, much easier to set breakpoits, much
easier to add code you're SURE will get run every time. Multiple entry
points went out with FORTRAN II, why do we still have multiple exit
points in this 21sh century?
Because there's one reason to enter a function ("Do this
specified thing") but many reasons the function might not be
able to do its job ("Logarithm of negative number" or "File
not found" or "Inauspicio us lunar phase").
Even the "not do its job" part is suspect: Some functions
can succeed in multiple different ways. "Item was present in
hash table" or "Item was not present but was inserted" or
"New file opened for output" or "Old file erased and truncated
to zero length, now ready for output."
Insisting that all modes of failure and all modes of success
must somehow filter down to one great holy return statement is
not good practice, but monotheism run rampant. "Thou shalt have
no RETURN before Me" -- pfui!
--
Eric Sosman es*****@acm-dot-org.invalid
Eric Sosman said:
<snip>
>
Insisting that all modes of failure and all modes of success
must somehow filter down to one great holy return statement is
not good practice, but monotheism run rampant. "Thou shalt have
no RETURN before Me" -- pfui!
Pfui schmui. This isn't about religion, but about clarity. If we can write
the code in a way that a maintenance droid will be able to understand
easily in five years' time, then that's a Good Thing. Personally, I find
code easier to understand if it doesn't arbitrarily leap off a cliff under
certain conditions, at apparently random intervals.
The thing that put me off multiple returns was not success/failure -
bail-out code is easy to understand, and the only caveat is "was it a clean
failure?" (e.g. let's remember to clean up memory, close any files that
shouldn't be open if the operation failed, etc etc). Rather, it was when I
was having to modify long-winded financial calculations that had return
statements sprinkled liberally through the (oversized) function.
Unravelling the "let's squeeze the last nanosecond out of this mainframe"
code so that I could do the mod properly was an exercise in torture. And
one of the worst culprits was this "oh, look, we're in six levels of loop,
this seems a suitably arbitrary place, so let's return the value of this
badly named variable. Or perhaps we should wait until we get to the next
loop, where we can return the value of an *even more* badly named
variable!"
I wouldn't want to put anyone through that. So I don't.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Richard Heathfield wrote:
Eric Sosman said:
<snip>
>> Insisting that all modes of failure and all modes of success must somehow filter down to one great holy return statement is not good practice, but monotheism run rampant. "Thou shalt have no RETURN before Me" -- pfui!
Pfui schmui. This isn't about religion, but about clarity. If we can write
the code in a way that a maintenance droid will be able to understand
easily in five years' time, then that's a Good Thing. Personally, I find
code easier to understand if it doesn't arbitrarily leap off a cliff under
certain conditions, at apparently random intervals.
The thing that put me off multiple returns was not success/failure -
bail-out code is easy to understand, and the only caveat is "was it a clean
failure?" (e.g. let's remember to clean up memory, close any files that
shouldn't be open if the operation failed, etc etc). Rather, it was when I
was having to modify long-winded financial calculations that had return
statements sprinkled liberally through the (oversized) function.
Unravelling the "let's squeeze the last nanosecond out of this mainframe"
code so that I could do the mod properly was an exercise in torture. And
one of the worst culprits was this "oh, look, we're in six levels of loop,
this seems a suitably arbitrary place, so let's return the value of this
badly named variable. Or perhaps we should wait until we get to the next
loop, where we can return the value of an *even more* badly named
variable!"
I wouldn't want to put anyone through that. So I don't.
Arguing that X is bad because you've seen bad examples of X isn't
very convincing, unless you can show that there are no /good/
examples of X.
The code you describe apparently fails the clarity test in at least
two other ways. (fx:assert) Code that /didn't/ fail those clarity
tests and used multiple returns can still be clear.
--
Chris "hashed up hashing" Dollin
"Who are you? What do you want?" /Babylon 5/
Chris Dollin said:
Richard Heathfield wrote:
<snip>
>> The thing that put me off multiple returns was [...]
I wouldn't want to put anyone through that. So I don't.
Arguing that X is bad because you've seen bad examples of X isn't
very convincing, unless you can show that there are no /good/
examples of X.
I'm not trying to argue that X is bad. I'm just pointing out that in *my*
experience I find X hard to maintain in general terms, and consequently I
don't like to inflict X on other people (including myself). Clarity takes
precedence over religion.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Richard Heathfield wrote:
Chris Dollin said:
>Richard Heathfield wrote:
<snip>
>>> The thing that put me off multiple returns was [...]
I wouldn't want to put anyone through that. So I don't.
Arguing that X is bad because you've seen bad examples of X isn't very convincing, unless you can show that there are no /good/ examples of X.
I'm not trying to argue that X is bad. I'm just pointing out that in *my*
experience I find X hard to maintain in general terms, and consequently I
don't like to inflict X on other people (including myself). Clarity takes
precedence over religion.
I think we agree on that last sentence. And, in practice, I suspect
our code might be more alike than disputes like this might suggest.
Is "Clarity takes precedence over religion." a religion?
--
Chris "(fx:quack) diagonal" Dollin
"We did not have time to find out everything we wanted to know."
- James Blish, /A Clash of Cymbals/
Chris Dollin said:
Richard Heathfield wrote:
<snip>
>Clarity takes precedence over religion.
I think we agree on that last sentence. And, in practice, I suspect
our code might be more alike than disputes like this might suggest.
I suspect you're right. All well-maintained roads lead to clarity.
Is "Clarity takes precedence over religion." a religion?
It's not clear.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Ancient_Hacker wrote:
Multiple entry points went out with FORTRAN II, why do we still have
multiple exit points in this 21sh century?
One can use setjmp() and longjmp() to create multiple entry points.
Or is that different? This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics |
by: malcolm |
last post by:
Example, suppose you have these 2 tables
(NOTE: My example is totally different, but I'm simply trying to setup
the a simpler version, so excuse the bad design; not the point here)
CarsSold {
CarsSoldID int (primary key)
MonthID int
DealershipID int
NumberCarsSold int
|
by: aj70000 |
last post by:
This is my query
select ano,max(date),a_subject from MY_TAB where table_name='xyz' and
ano=877
group by a_subject,ano order by a_subject
ANO max(Date) A_Subject
877 2005-01-20 00:00:00.000 Subject_1
877 1900-01-01 00:00:00.000 Subject_2
877 2004-12-20 00:00:00.000 Subject_3
|
by: JJ_377 |
last post by:
Can someone tell me why SQL seems to ignore my order by clause?
I tried to run through the debugger, but the debugger stops at the
select statement line and then returns the result set; so, I have no
idea how it is evaluating the order by clause.
THANK YOU!
CREATE proc sprAllBooks
@SortAscend varchar(4),
@SortColumn varchar(10)
|
by: Chris, Master of All Things Insignificant |
last post by:
I have come to greatly respect both Herfried & Cor's reponses and since the
two conflicted, I wanted to get some clarification.
My orginal post:
Herfried, maybe your example here can get you to answer a question I've
wondered about for a while.
With Me.Label1
.Text = ...
.Refresh()
|
by: Sean Shanny |
last post by:
To all,
We are running postgresql 7.4.1 on an G5 with dual procs, OSX 10.3.3
server, 8GB mem, attached to a fully configured 3.5TB XRaid box via
fibre channel.
I think we have run into this issue before but I thought the code was
fixed. :-(
I have the following SQL:
| |
by: GreatAlterEgo |
last post by:
Hi,
This is my query which is embedded in a COBOL program.
EXEC SQL
SELECT DATE, AGE, DURATION, AMT
INTO :LDATE, :L.AGE, :L.DURATION, :L.AMT
FROM TAB1
WHERE CODE = :KEY.CODE
AND SET = :KEY.SET
AND DATE <= :KEY.DATE
|
by: metaperl.etc |
last post by:
A very old thread:
http://groups.google.com/group/comp.lang.python/browse_frm/thread/2c5022e2b7f05525/1542d2041257c47e?lnk=gst&q=for+else&rnum=9#1542d2041257c47e
discusses the optional "else:" clause of the for statement.
I'm wondering if anyone has ever found a practical use for the else
branch?
|
by: Jim.Mueksch |
last post by:
I am having a problem with using calculated values in a WHERE clause.
My query is below. DB2 gives me this error message: Error: SQL0206N
"APPRAISAL_LESS_PRICE" is not valid in the context where it is used.
SQLSTATE=42703
SELECT DISTINCT S3.OPR_APPLICATION_NR,
S3.APPLICATION_ID,
S3.APPRAISAL_TYPE_CD,
S3.Appraisal_Used_Amount,
S3.RPT_LEVEL2_NR,
|
by: pwiegers |
last post by:
Hi,
I'm trying to use the result of a conditional statement in a where
clause, but i'm getting 1)nowhere 2) desperate :-)
The query is simple:
--------
SELECT
idUser,
(@ageraw:=YEAR(CURRENT_DATE()) - YEAR(dateofbirth) -
|
by: jackal_on_work |
last post by:
Hi Faculties,
I have two queries which give me the same output.
-- Query 1
SELECT prod.name, cat.name
FROM products prod INNER JOIN categories cat
ON prod.category_id = cat.id
WHERE cat.id = 1;
|
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: Oralloy |
last post by:
Hello folks,
I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>".
The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed.
This is as boiled down as I can make it.
Here is my compilation command:
g++-12 -std=c++20 -Wnarrowing bit_field.cpp
Here is the code in...
|
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: isladogs |
last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM).
In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules.
He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms.
Adolph will...
|
by: TSSRALBI |
last post by:
Hello
I'm a network technician in training and I need your help.
I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs.
The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols.
I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
|
by: adsilva |
last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
|
by: 6302768590 |
last post by:
Hai team
i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
| |
by: muto222 |
last post by:
How can i add a mobile payment intergratation into php mysql website.
|
by: bsmnconsultancy |
last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...
| |