Sharing code between cases

G

Greg Schmidt

I'm wondering what the "best" is way to handle blocks of code that are
shared between two or more cases in a switch statement. Consider the
following code (assuming valid variable and function definitions,
obviously):

switch (a)
{
case 1:
if (x) return false;
y = 6;
foo();
break;

case 2:
if (x) return false;
y = 6;
bar();
break;

case 3:
foo();
break;
}

Of course, this isn't too bad, but when the first two lines turn into a
dozen, or as there are more cases that share common code, the
possibility of a change to one not being reflected to all others
increases. Generally, the solution to common code is to pull it out,
but the ways that I see of doing that here are:

1) Sequential switches
switch (a)
{
case 1:
case 2:
// shared code here
}
switch (a)
{
// unique code here
}
This might also be written like
if (a == 1 || a == 2)
{
// shared code here
}
depending on whether there were multiple different blocks of shared
code.

This method looks potentially confusing, and perhaps causes maintenance
problems.

2) Put the common code in a function that is called from each applicable
case. This would work well in some cases, but not, I think, if there
are multiple possible early return values that might be generated,
multiple variables that may be tested or affected (which now all need to
be parameters to the function), etc.

Exceptions could be a way to solve the "multiple return value" part of
the problem with this solution.


So, are there other methods I've missed that people use in this
situation? Is this perhaps an indication that I'm trying to use one
variable to control two orthogonal values (time to refactor)?
 
G

Gernot Frisch

Greg Schmidt said:
I'm wondering what the "best" is way to handle blocks of code that
are
shared between two or more cases in a switch statement. Consider
the
following code (assuming valid variable and function definitions,
obviously):

switch (a)
{
case 1:
if (x) return false;
y = 6;
foo();
break;

case 2:
if (x) return false;
y = 6;
bar();
break;

case 3:
foo();
break;
}

I do this - and I know this is considered crappy style and everyone
will flame me now - for it's fast to write:

#define DEF1 {if (x) return false; y=6;}

switch(a)
{
case 1: DEF1
foo();
break;
case 2: DEF2
bar();
break;
case 3:
foo();
break;
}

any, yes, I do this for very long blocks as well.
-Gernot
 
R

Richard Herring

In message <[email protected]>, Greg Schmidt

[switch() complications snipped]
So, are there other methods I've missed that people use in this
situation? Is this perhaps an indication that I'm trying to use one
variable to control two orthogonal values (time to refactor)?

Maybe, but don't just do the obvious and split it into two values. When
a variable is controlling complex *behaviour*, it looks like a hint that
you need to represent that behaviour by polymorphic classes. Then
instead of

switch(a)
{
/* lots of cases, lots of stuff */
}

you'll have

p->DoStuff();
 
N

Noah Roberts

Greg said:
Exceptions could be a way to solve the "multiple return value" part of
the problem with this solution.

I am really surprised nobody else jumped on this one.

Exceptions are not another way to return values. Exceptions are for
exceptional situations and should not be used for flow control or
returns. That is a misuse of the feature and contains all sorts of
bugbears that love to eat lost programmers.
 
A

Andrey Tarasevich

Greg said:
I'm wondering what the "best" is way to handle blocks of code that are
shared between two or more cases in a switch statement. Consider the
following code (assuming valid variable and function definitions,
obviously):

switch (a)
{
case 1:
if (x) return false;
y = 6;
foo();
break;

case 2:
if (x) return false;
y = 6;
bar();
break;

case 3:
foo();
break;
}
...
1) Sequential switches
...

Wouldn't nested switches be more elegant than sequential ones?

switch (a)
{
case 1:
case 2:

// Common prologue
if (x) return false;
y = 6;

// Specific code (branched with 'if' or 'switch')
switch (a)
{
case 1: foo(); break;
case 2: bar(); break;
}

// Common epilogue
// ...

break;

case 3:
foo();
break;
}
 
G

Greg Schmidt

In message <[email protected]>, Greg Schmidt

[switch() complications snipped]
So, are there other methods I've missed that people use in this
situation? Is this perhaps an indication that I'm trying to use one
variable to control two orthogonal values (time to refactor)?

Maybe, but don't just do the obvious and split it into two values. When
a variable is controlling complex *behaviour*, it looks like a hint that
you need to represent that behaviour by polymorphic classes. Then
instead of

switch(a)
{
/* lots of cases, lots of stuff */
}

you'll have

p->DoStuff();

You may be right. The library where I'm currently having this issue
(which I did most of the design for) actually makes extensive use of
polymorphism, but for some reason I had a mental block to seeing that it
might work in this case too.
 
G

Greg Schmidt

I am really surprised nobody else jumped on this one.

Exceptions are not another way to return values. Exceptions are for
exceptional situations and should not be used for flow control or
returns. That is a misuse of the feature and contains all sorts of
bugbears that love to eat lost programmers.

I'm sure if you search the archives, you'll find that this is another
one of the religious issues that comes up from time to time. I think it
depends largely on the situation. When I wrote that, I was thinking
that the multiple return values would actually tend to be codes for
different error situations, in which case an argument can be made that
"error" and "exception" can be (close to) synonymous. Certainly, using
an exception to return the result of, say, a mathematical calculation is
an abuse of the feature.

In my original, hypothetical situation, since the exception would be
thrown from the newly-created "shared code" function, which won't be
useful anywhere except very locally, the switch could be nested inside a
try block, and the catch would be right there to trap the exception and
return a "normal" result back to the caller. No need to worry about the
exception biting the unwary when its use is so limited.
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

Noah said:
In "Thinking in C++" Eckel explains the use of exceptions as to deal
with 'exceptional' situations. In other words, the unexpected. He also
uses them to enforce function contract (or preconditions). So for
instance you wouldn't use an exception upon end of file, because that is
an expected situation, but you would if the file suddenly became

That depends. If you are reading a text file, the end of file is the normal
condition to mark the end of the text, but if you are reading for example a
file in a format that defines precisely what contains and what are the
lengths of each part, reaching end of file in the middle of a file can be
considered an excpetional condition (file is corrupt or is not in the
required format).
 
N

Noah Roberts

Julián Albo said:
That depends. If you are reading a text file, the end of file is the normal
condition to mark the end of the text, but if you are reading for example a
file in a format that defines precisely what contains and what are the
lengths of each part, reaching end of file in the middle of a file can be
considered an excpetional condition (file is corrupt or is not in the
required format).

Sure. Good point.
 
G

Greg Schmidt

In "Thinking in C++" Eckel explains the use of exceptions as to deal
with 'exceptional' situations. In other words, the unexpected. He also
uses them to enforce function contract (or preconditions). So for
instance you wouldn't use an exception upon end of file, because that is
an expected situation, but you would if the file suddenly became
unreadable or disconnected without an eof.

http://groups-beta.google.com/group..._frm/thread/505fb002577795f2/fac713555b51a81c
is a lengthy thread with various views on this. It seems that Herb
Sutter (who knows a thing or two about exceptions) perhaps falls closer
to my view than yours, but then I may be reading my own bias into his
posts, or he may have changed his views since then (it was over 4 years
ago).
Oh I don't think so. I think it poorly advised to allow bad design to
creap into "local" functions that won't be used elsewhere for some
unforseen reason down the road. Simply because those reasons are
unforseen. When you make a function you should always assume you might
use it in ways you are not expecting to right now.

I used to agree with you, but I've since discovered that it is more
efficient to design for what you need now, and accept that the design
may need to be changed in the future, than it is to design for any
possible eventuality. If only I could get back all the time I spent
coding for possible future cases that never happened!
 
N

Noah Roberts

Greg said:
I used to agree with you, but I've since discovered that it is more
efficient to design for what you need now, and accept that the design
may need to be changed in the future, than it is to design for any
possible eventuality. If only I could get back all the time I spent
coding for possible future cases that never happened!

You don't need to code for all possibilities, not even possible. Just
don't code assuming things that shouldn't be assumed.
 
I

Ioannis Vranos

Greg said:
I'm wondering what the "best" is way to handle blocks of code that are
shared between two or more cases in a switch statement. Consider the
following code (assuming valid variable and function definitions,
obviously):

switch (a)
{
case 1:
if (x) return false;
y = 6;
foo();
break;

case 2:
if (x) return false;
y = 6;
bar();
break;

case 3:
foo();
break;
}


What about this:


if(x)
{
// Or switch for more
if(a!=3)
return false;

// ...

}

else
{
switch(a)
{
case 1:
{
y = 6;
foo();
break;
}

case 2:
{
y = 6;
bar();
break;
}
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,024
Latest member
ARDU_PROgrammER

Latest Threads

Top