Mombu the Programming Forum sponsored links

Go Back   Mombu the Programming Forum > Programming > Reasons for single entry, single exit
User Name
Password
REGISTER NOW! Mark Forums Read

sponsored links


Reply
 
1 19th August 09:04
john potter
External User
 
Posts: 1
Default Reasons for single entry, single exit


Just in case there are others unable to set fixed pitch font.

John

int f (int v) {
int x;
if (v < 7)
x = 1;
else if (v < 20)
x = 2;
else
x = 3;
return x;
}

int f (int v) {
int x;
if (v < 7) {
x = 1;
goto done;
}
if (v < 20) {
x = 2;
goto done;
}
x = 3;
done :
return x;
}

int f (int v) {
if (v < 7)
return 1;
if (v < 20)
return 2;
return 3;
}

int f (int v) {
return v < 7 ? 1
: v < 20 ? 2
: 3;
}

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
  Reply With Quote


  sponsored links


2 19th August 09:05
john potter
External User
 
Posts: 1
Default Reasons for single entry, single exit


news:<9881gvs0btk7cj3aoeul4tqkbutca4rvqh@4ax.com>. ..


Actually, it started as a rebutal to the claim that SE increased the
McCabe complexity. Still no example where it does.

Yes. Herb pinned me down. Functions are SE by nature. The only way
out is back to the call site. I am interested in structured programming
in any language and it may be that I have a very loose definition.
That's fine by me because I am looking for a way to accept some codes
with multiple return statements and reject others. The McCabe graph
will provide this. It is very easy to say "One return statement" and
enforce it. It will be McCabe clean, but there may be alternatives.


The problem seems to be the difference between structured code and SE
structures. If we look at the first if statement above, there are two
ways out of it. One is to the next statement and the other is to the
end of the function. The statement is not SE, but the code does not
show the unstructured characteristic. When reduced to assembly, all
of them are the same and best represented by the if-goto version.

If I look at the four versions with sequential SE structures in
mind, I see.

three statements: int if return
five statements: int if if = return
three statements: if if return
one statement: return

The first is what we do not want SE to produce. The second is not
something we want to write, but the third looks the same. It
produces structured code in an abnormal way via jump statements. If
it is really clearer, I want a way to accept it without opening the
door to a flow of spaghetti.

Consider min.

int& min1 (int& a, int& b) {
return b < a ? b : a;
}
int& min2 (int& a, int& b) {
if (b < a)
return b;
else
return a;
}
int& min3 (int& a, int& b) {
if (b < a) return b;
return a;
}
int& min4 (int& a, int& b) {
int* x;
if (b < a)
x = &b;
else
x = &a;
return *x;
}
int& min5 (int& a, int& b) {
int* x;
if (b < a) {
x = &b;
goto done;
}
x = &a;
done :
return *x;
}
int& min6 (int& a, int& b) {
int* x(&a);
if (b < a)
x = &b;
return *x;
}

I am interested in hearing why anyone would prefer anything
to min1. I will note that min6 is likely to receive complaints,
but is the only one which generalizes.

If we go back to the original realloc code, it turns out to also
be McCabe clean. The key is that there is no nested return. If
structured use of jump statements is good, there should be some
way to identify it. It is clear that no use of return may be
unfactored to be inlined by the programmer. Is that bad? Just
to make sure the question is understood.

int& w(minN(x, y));

Versions 1, 4, 5, 6 may be used inline. Remove the function
header, copy the code to return, replace the call with the
expression in the return statement. Replace identifiers as
needed. Versions 2, 3 must be rewritten.

To answer your question, the McCabe graph gives me the extra
rule that I wanted to identify what multiple uses of return
are acceptable. It looks like those cases are exactly the
cases which can be rewritten nicely as ?:. Since I prefer
that form, I have no use for multiple returns. If used, I
still want a visual clue. The only way I see for that is
to write in the form of version 3 where the return is on the
same line as the if. The missing body is the signature of
the jump. That restriction forces refactoring to the point
where the ?: form is obvious.

The argument that code is readable when it may be ****yzed
sequentially seems like a mystery novel approach. I see
code as a blueprint, not a novel.

The McCabe graph shows that the find version with two returns
is unstructured. It provides a quantified measure. No need
to talk about one code being more X than another with ill
defined X.

John

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
  Reply With Quote
3 19th August 09:05
External User
 
Posts: 1
Default Reasons for single entry, single exit


I wonder if this isn't the key to our differences. I know that I am in
the strictly SESE camp. But perhaps the main reason is that SEME seems
to be function-does-to-much-prone, as witnessed by the code samples I've
seen.

I know that in practice, every time I've had to work on an SEME (where
M > 1 -- I appreciate the fact the SESE is a subset of SEME, and that
none of the people here want to insist on a second exit when it isn't
appropriate), I've rewritten it as SESE. In almost every case, however,
I've also broken it up into several different functions as well. Not
because SESE imposed the factoring, but because the function was doing
too many things at once.

I'm sure you've seen the sort of thing I mean: a function with 40 or 50
lines, five levels of nested conditionals and loops, and returns spread
out in some of the conditionals. And I'm equally sure that neither you
nor Dave Harris approve of such things, independantly of the SESE/SEME
arguments. While I globally agree with John, and admire his courage,
I've pretty much given up arguing it: if the functions are small enough
and homogenous enough, the difference between the two styles isn't
critical -- I can read either.

--
James Kanze GABI Software mailto:kanze@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, Tél. : +33 (0)1 30 23 45 16

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
  Reply With Quote
4 19th August 09:06
john potter
External User
 
Posts: 1
Default Reasons for single entry, single exit


I seem to be missing your point. Example?

John

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
  Reply With Quote
5 19th August 09:06
belvis
External User
 
Posts: 1
Default Reasons for single entry, single exit


Thanks for the clarification; I misunderstood. It seems that McCabe
graphs don't really support either SEME or SESE, since you can produce
good SEME and SESE code as well as bad (as measured by McCabe graphs).

Here's my take on this debate:

Whenever implementing a function, I have to satisfy (broadly speaking)
two goals:

-- implement the desired behavior
-- follow naming conventions, style guides, coding conventions, etc.

It's my opinion that we want to skew our mental effort to the first
goal as much as possible.

(Note: In this post I'm speaking only about implementation, as opposed
to other activities such as ****ysis or design, where we do need to
spend more effort on things besides simple correctness.)

Obviously, if these two goals ever conflict, satisfying the first goal
has to take precedence.

This suggests a criterion for evaluating subgoals for inclusion in the
second goal: any subgoal that conflicts with the first goal (i.e.,
interferes with function correctness) should be left out. (This is why
I look at rules like "never use exceptions" or "never dynamically
allocate memory" with skepticism; such rules can easily interfere with
correctness.)

Note that, for the most part, naming conventions, indenting styles and
so forth don't conflict with correctness. The only way these things
interact with correctness is if the conventions in use are foreign
enough to a programmer as to be error-prone.

This suggests a second criterion: any subgoal under consideration for
inclusion in the second goal should require relatively little mental
effort, because the more effort required, the more likely the subgoal
will lead to errors. For example, a formatting convention that has
programmers place each token on a separate line with no indenting
would involve a great deal of effort to both read and write correctly,
so it isn't a very good convention. On the other hand, a rule like
"open curly braces always go on the next line," while it may seem
distateful to some, can be used with almost no mental overhead, and is
therefore worth considering.

So where do SESE and SEME come in? Obviously, they don't interact
directly with correctness (many functions can be either SESE or SEME
and still be correct), so they belong (if anywhere) in the second
goal. Second, SESE vs. SEME is not an exclusive choice, because
sometimes, while following SEME guidelines, I will write a SESE
function, simply because, for that function, SESE is the only sensible
option. The choice is therefore between SESE-only vs. a SESE/SEME
combination.

For myself, I reject the SESE-only choice because it leads to
situations where I have to spend too much effort on the second goal --
eventually I will have to implement a function for which I will have
to spend significant mental effort on something other than
correctness: simply getting the function to be SESE.

I don't have an example handy, but at various times during my career
I've had to program in an SESE style, and eventually, I come to a
function for which getting the function to be SESE involves effort on
par with the effort of just getting the function correct. As a result,
I've had to fix bugs that existed simply because a function was
written to have a single exit, where a multiple-exit function would
have been simpler to implement and therefore less likely to have bugs
in the first place. I don't know how to characterize such functions,
other than to say that they are more complex when implemented as SESE.

If you've managed to read this far, you have no doubt noticed that
what I've written is very subjective. It's all my opinion, but I
believe that the ideas I've laid out can provide a useful framework
for discussing the issues (not just SESE vs. SEME, but other "second
goal" type issues).

Further, objective complexity measures are all well and good, but
subjective complexity is extremely important as well; after all, the
code will have to be written and maintained by people with subjective
impressions of what's complex and what's not.

Therefore, I think it's perfectly valid to have coding rules like "use
multiple exit wherever it makes sense." Such a rule is no more
subjective than "never use multiple exit."

Bob Bell

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
  Reply With Quote
6 19th August 09:07
bart van ingen schenau
External User
 
Posts: 1
Default Reasons for single entry, single exit


On 2 Jul 2003 12:59:10 -0400, John Potter <jpotter@falcon.lhup.edu>

I disagree.
Since new can throw an exception, there are two paths through the
function (executing all statements, and direct exit due to an
exception). I believe this makes the complexity two.

Bart v Ingen Schenau

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
  Reply With Quote
Reply


Thread Tools
Display Modes




Copyright © 2006 SmartyDevil.com - Dies Mies Jeschet Boenedoesef Douvema Enitemaus -
666