In my program I have a structure similar to the following one:
while (true) {
int c;
cout << "Type a command: ";
cin >> command;
switch (c) {
case 1:
// [...]
if (!condition) break;
// [...]
if (!condition2) break;
// [...]
if (!condition3) break;
// [...]
break;
case 2:
// [...]
break;
default:
break;
}
}
But our professor told us to never use the break except in the switch case to exit... I was wondering if there's a better and smarter way to replace the block if(!condition) break;.
My main goal is to prevent the program from doing certain actions if condition is not verified.
In order to avoid break you need to use the opposite condition, and instead of breaking the flow, control it:
switch (c) {
case 1:
// [...]
if (condition) {
// [...]
if (condition2) {
// [...]
if (condition3) {
// [...]
} // if the third condition is false, you will continue to the break.
} // if the second condition is false, you will continue to the break.
} // if the first condition is false, you will continue to the break.
break;
// ...
}
EDIT
To avoid complex conditions, you can use functions:
void condition_1_actions();
void condition_2_actions();
void condition_3_actions();
// ... main ...
case 1:
if (condition) condition_1_actions();
break;
// ... After main ...
condition_1_actions() {
// do some actions
// Calculate condition2 or pass it as parameter
if (condition2) condition_2_actions();
}
condition_2_actions() {
// do some actions
// Calculate condition3 or pass it as parameter
if (condition3) condition_3_actions();
}
condition_3_actions() {
// do some actions
}
I'm sure that "your professor" would agree: "if it ain't broke, don't fix it."
The logic as-written is clear, and I presume that it works. Also, as-written it would be maintainable: I wouldn't have to radically change the source-code if when I needed to add a new condition to it. Just leave it alone. Anything that you hear from a professor – or anyone else – is a guideline!
"Clarity" is always key, because as years go by your source-code is going to be added-to by many others. I like the original idiom because each of the cases is clearly distinct: "make this test, and then bail-out." (Could be break or return depending on the situation.) It's very easy to see how the logic goes, and it's equally easy to add another case to it "in the same vein."
In the end – "it makes absolutely no difference to the digital computer." (As Perl programmers like to say, "there's more than one way to do it.™") But it might be attractive to your [future ...] colleagues. There are no absolutes here. Just try to be nice to them. Be "stupid-obvious."
Related
I was thinking, is there any way you can use throw/try/catch without closing the program?
For example:
function
{
restore point:
//code goes here
try "something";
goto restore point;
}
Is there any method to call function and, if the condition is not verified in try statement, to go back to identifier?
Here`s my case:
int Automat::Retragere()
{
int suma;
cout<<"\n Introduceti suma pe care doriti s-o retrageti: ";
cin>>suma;
if(suma > 5000){
throw "\n Suma este mai mare decat plafonul maximal zilnic.";
}
else{
if(suma > sold){
throw "\n Suma este mai mare decat SOLDUL curent.";
}
else{
cout<<"Operatiune efectuata cu succes.";
sold = sold - suma;
return 1;
}
}
}
marcaj2:
//code here
switch(optiune){
case 1:
Retragere();
goto marcaj2;
case 2:
Depunere();
goto marcaj2;
case 3:
Transfer();
goto marcaj2;
default:
break;
}
I`m asking if, after calling "Retragere" function, is there a posibility to go back to my identifier in case try encounters an error.
In the case you present, Automat::Retragere should probably not throw any exceptions but just return error codes describing what was wrong, since "input too large" (larger than allowed or larger than sum on account) are not really exceptional states. Use an enum with speaking names for that instead of plain int. With a simple return value you are free to use ordinary control flow like a while loop for the input until the number is allowed etc.
Design interlude: That would be different if this was a routine expecting sanitized input so that these conditions indicate a program error. In fact, one should probably already at this stage separate data acquisition from business logic.
This means here that one function is responsible for obtaining the input and checking it; another function would expect valid input (no strings, but a number indicating a valid amount) and perform the actual business action like withdrawel or deposit. It's only a one-liner here but in the real world may involve establishing a connection of some sort, authentication etc.
The business function could throw when presented with an invalid number, because the data provider broke its contract.
Concerning the technical aspect of your question: The 2011 standard says in 15/3:
A goto, break, return, or continue statement can be used to transfer
control out of a try block or handler.
I cannot imagine any ordinary reason to do that, but it is not illegal. (Some of the provisions surrounding goto, arguably even goto proper, target machine generated code or similar scenarios.)
It may well be possible to handle certain exceptions locally; a saner approach (saner than goto directly from inside the catch block to somewhere in the function) would be to have the try/catch block in a loop. The catch block would examine the exception and either set an error code which is then checked in the loop condition, or possibly re-throw exceptions which are unknown or too severe to recover from locally.
Is this what you are looking for?
bool done = false;
while (!done)
{
//marcaj2:
switch(optiune){
case 1:
Retragere();
break; // break out of the switch, i.e. will continue at while (!done)
// so it similar to goto marcaj2
case 2:
Depunere();
break;
case 3:
Transfer();
break;
default:
done = true; // end the while loop
break;
}
}
Others have already commented that the exception throw is bad.
But if you really want it, I think you can do it something like:
bool done = false;
while (!done)
{
try
{
//marcaj2:
switch(optiune){
case 1:
Retragere();
break; // break out of the switch, i.e. will continue at while (!done)
// so it similar to goto marcaj2
case 2:
Depunere();
break;
case 3:
Transfer();
break;
default:
done = true; // end the while loop
break;
}
}
catch (...)
{
// error handling...
}
}
How to execute all cases in switch statement without duplicating existing in big "all-in-one" case ?
For e.g.
switch(obj.nObjType)
{
case eElephant:
...
break;
case eFoo:
...
break;
case eSeptember:
...
break;
default:
return;
}
I want force executing code for all 3 cases (eElephant, eFoo, eSeptember) like there is no break;, for example in case of nObjType = eAllTypes .
You can't just ignore a break. Rather, restructure your code.
switch(obj.nObjType) {
case eElephant:
pokeElephant();
break;
case eFoo:
barTheFoo();
break;
case eSeptember:
rememberSeptember();
break;
case eAllTypes:
pokeElephant();
barTheFoo();
rememberSeptember();
break;
default:
return;
}
Then use if statements:
if (obj.nObjType == eElephant || obj.nObjType == eAllTypes)
{
// Elephant code
}
if (obj.nObjType == eFoo || obj.nObjType == eAllTypes)
{
// Foo code
}
// etc.
This answer is how it should be done.
However:
I can see, it's hard to find as right solution without generating lots
of code lines. Thanks #TobiMcNamobi, but in my switch there is about
200 of cases, so creating a function for each case is not a good idea.
I think, the best can be (unfortunately) duplicating all cases in a
big one. Because, I suppose, if else is much less efficient then
switch statement ?
With this many cases (what on earth are you working on?) even extracting methods leaves you with 200 extra function calls in the body of your switch statement. This could get harder to maintain quickly.
In this case, I would do the following:
switch(enum_variable)
{
case e_all:
case e_1:
e_1_function();
if(enum_variable != e_all){break;} //**
case e_2:
e_2_function();
if(enum_variable != e_all){break;} //**
//...
default:
break;
}
The lines marked //** will break when not doing all cases. It is quick to implement (can be done with a search and replace of break; which speeds things up for you) and does what you want.
With that said, it's still a pretty terrible way of doing it, but exceptions do sometimes have to be made.
I do however recommend that you do not turn to this as a style to use in the future. You may find that you can do better by re-thinking the workflow of your project, as this will probably allow you to simplify and improve. Of course, we don't know what you are working on, so I can't offer more advice.
If you put your switch statement in a function, and make your obj have a list of flags rather than a flag, you can call the function with the switch statement for each flag in the list. Pseudo:
void dostuff(flag)
switch(flag) {
// ...
}
}
for (auto flag in obj.flags) {
dostuff(flag)
}
Is there a better (or cleaner) way to write the following code?
if(conditionX)
{
if(condition1)
{
// code X1
}
else if(condition2)
{
// code X2
}
}
else if(conditionY)
{
if(condition1)
{
// code Y1
}
else if(condition2)
{
// code Y2
}
}
I have a few more conditions, but I guess you get the point.
There are four approaches to this problem, none of which is universal:
Leave everything as is - There isn't much code duplication here. If computing condition1 and condition2 is tricky, compute them upfront and store them in bool variables
Make conditionX and conditionY produce a result that lets you unify condition1 and condition2 - This is not always possible, but in some situations you could prepare a variable that unifies the activities taken in the two branches, say, by using a function pointer or a lambda.
Put the processing logic into subclasses with virtual functions to eliminate conditional logic - This is possible only when your initial design missed an opportunity to subclass. Essentially, this approach pushes the decision on conditionX/conditionY into a place where a subclass is created, and then "reuses" that decision later on by calling a proper override of a virtual function in the interface.
Create a numeric combination representing all three conditions, and convert to switch - This trick unifies the conditionals, reducing the nesting.
Here is an example of the last approach:
int caseNumber = ((conditionX?1:0) << 3)
| ((conditionY?1:0) << 2)
| ((condition2?1:0) << 1)
| ((condition1?1:0) << 0);
switch (caseNumber) {
case 0x09:
case 0x0D:
case 0x0F: // code X1
break;
case 0x0A:
case 0x0E: // code X2
break;
case 0x05:
case 0x07: // code Y1
break;
case 0x06: // code Y2
break;
}
If your concern is with clean code in terms of viewing the source, my advice would be to segregate the blocks into their own sections, something like:
if (conditionX) processConditionX();
else if (conditionY) processConditionY();
and so on.
Then, in the sub-functions, you place the "meat":
void processConditionX (void) {
if(condition1) {
// code X1
} else if(condition2) {
// code X2
}
}
You can modify it to pass in and return parameters as necessary and I'd make the conditions and function names a little more descriptive, though I assume they're just examples here.
You can implement a state-machine instead:
#define COMBINATION(a,b,c,d) (((a)<<3)|((b)<<2)|((c)<<1)|((d)<<0))
switch (COMBINATION(conditionX,conditionY,condition1,condition2))
{
case COMBINATION(0,0,0,0): break;
case COMBINATION(0,0,0,1): break;
case COMBINATION(0,0,1,0): break;
case COMBINATION(0,0,1,1): break;
case COMBINATION(0,1,0,0): break;
case COMBINATION(0,1,0,1): CodeY2(); break;
case COMBINATION(0,1,1,0): CodeY1(); break;
case COMBINATION(0,1,1,1): CodeY1(); break;
case COMBINATION(1,0,0,0): break;
case COMBINATION(1,0,0,1): CodeX2(); break;
case COMBINATION(1,0,1,0): CodeX1(); break;
case COMBINATION(1,0,1,1): CodeX1(); break;
case COMBINATION(1,1,0,0): break;
case COMBINATION(1,1,0,1): CodeX2(); break;
case COMBINATION(1,1,1,0): CodeX1(); break;
case COMBINATION(1,1,1,1): CodeX1(); break;
}
This includes only one branch operation, so it is possibly a little more efficient (even though it also includes an additional runtime computation (at the switch line)).
As to being cleaner, I guess it's a matter of perspective, but the template above also gives you a convenient way to detect all unhandled branches within your code.
Please note that if any of the condition variables may have a value other than 1 or 0, then you should:
#define COMBINATION(a,b,c,d) (((a)?8:0)|((b)?4:0)|((c)?2:0)|((d)?1:0))
Update (attributed to #Jonathan Wakely in one of the comments below):
If you're using C++11, then you may replace the COMBINATION macro with a constexpr function:
constexpr int COMBINATION(bool a,bool b,bool c,bool d)
{
return ((int)a<<3) | ((int)b<<2) | ((int)c<<1) | ((int)d<<0);
}
I would provide the decision inside the first if as a parameter to a separated functions which then decides which code to execute, like:
if(conditionX)
{
Method1(Condition Parameters)
}
else if(conditionY)
{
Method1(Condition Parameters)
}
Another way would be to provide all needed info to a decision method (matrix), this method returns an integer which you use in a switch statement to decide which code to execute. In this way you separate the desicion logic which makes it readable and easy to unittest if needed:
DecisionMatrix(conditionX, conditionY, condition1, condition2)
{
// return a value according to the conditions for Example:
// CoditionX + Condition1 => return 1
// CoditionX + Condition2 => return 2
// CoditionY + Condition1 => return 3
// CoditionY + Condition2 => return 4
}
switch(DecisionMatrix)
{
case 1: //run code X1
break;
case 2: //run code X2
break;
case 3: //run code Y1
break;
case 4: //run code Y2
break;
}
The best way here would be to use polymorphism (Only if the chunks of code are huge)
If they are small code snippets, creating classes would obviously be an overkill.
Therefore, if there is similarity in all codes, I'd suggest a seemingly easy but really difficult task.
Try to parametrize them as much as you can.
Create a function that takes those and call them in the conditions
Now the code would be in function blocks and "cleaner"
It is always difficult to create simple things.
if (conditionX) {
method(parameterX);
else if (conditionY) {
method(parameterY);
}
where
void method(ParameterType e) {
if (condition 1) {
// Code in terms of parameter e
} else if (condition2) {
// Code in terms of parameter e
}
}
The condition that you can parametrize should be kept outside.
Hope this helps.
I think this way can be another way for solving your code.
enum ConditionParentType
{
CONDITION_NONE = 0,
CONDITION_X,
CONDITION_Y,
};
enum ConditionChildType
{
CONDITION_0 = 0,
CONDITION_1,
CONDITION_2,
};
class ConditionHandler
{
public:
explicit ConditionHandler(ConditionParentType p_type, ConditionChildType c_type)
: p_type_(p_type), c_type_(c_type) {};
void DoAction()
{
if(child_type == CONDITION_1)
{
}
else if(child_type == CONDITION_2)
{
}
else
{
//error
}
}
private:
const ConditionParentType p_type_;
const ConditionChildType c_type_;
};
int main(int argc, char *argv[])
{
ConditionParentType parent_type = GetParentType();
ConditionChildType child_type = GetChildType();
ConditionHandler handler(parent_type, child_type);
handler.DoAction();
getchar();
return 0;
}
If the combination of conditions means something then I'd write a set simple methods that return boolean values. You would end up with something like:
if (first-condition(conditionX, condition1)) {
// code X1
} else if (first-condition(conditionX, condition2)) {
// code X2
} else if (third-condition(conditionY, condition1)) {
// code Y1
} else if (fourth-condition(conditionY, condition2)) {
// code Y2
}
The names of the methods describe the conditions. Don't worry that the methods are only called once (the compiler will probably in-line them anyway), the important bit it that your code then becomes self documenting.
I'm quite surprised by the other suggested answers, which are mostly wrong if:
The two repeated conditions condition1 or condition2 are complex, in which case DRY comes into play, or
Any of the four conditions have side effects, or
Any of the conditions are slow (for example, find the minimum of a large array, or read a file), or
A boolean short-circuit is needed, as in: if (p == 0) {...} else if (p->foo == 42) {...}.
If none of these hold, as is the case 99.42% of the time, then leave the code as it is. Or, as a minor variation, change it so the nesting (that is, indentation) is only one level, not two.
Otherwise, you will need to use temporary variables as follows
const bool tstX = (conditionX);
const bool tstY = tstX || (conditionY);
const bool tst1 = tstY && (condition1);
const bool tst2 = tstY && !tst1 && (condition2);
the original code doesn't look to bad. Depending on the specific case it may or may not be more readable to do something like:
if(conditionX and condition1) {
// code X1
}
else if(conditionX and condition2) {
// code X2
}
else if(conditionY and condition1) {
// code Y1
}
else if(conditionY and condition2)
// code Y2
}
I have a switch like thus (written in cfscript):
switch (something) {
case "stuff":
if(this eq that){
writeDump("hello");
} else { /* do other? */ }
break;
case "other":
//do something else
break;
}
In my else, I want to be able to tell it that I want the "other" case to be invoked. Is this possible? (I seem to remember doing this in other languages.)
There is no GOTO construct in CF, no. And that's pretty much what you're asking for.
If your switch is really as simple as you indicate, and you want to fall through to the NEXT case when the condition is false, what you could do is to have the break statement in the true branch of the if clause, and have no break statement in the false branch. Then when the false branch runs, processing will not exit the case when it's done; it'll fall through to the next case.
As Adam explained, it is possible, here is some code to show how:
something = "stuff";
test = "more stuff";
switch (something) {
case "stuff":
if(test eq "more stuff"){
writeOutput("<p>Something</p>");
break;
}
case "other":
writeOutput("<p>something Else</p>");
break;
}
Change the values of 'something' and 'test' to see different results. When using a switch in cfscript, if there is no 'break' then ColdFusion will continue processing the cases until it hits one.
As far as I'm aware that's not possible. You'll need to use an if else statement, or nested is/else, instead of the switch.
something = "other";
if (something eq "stuff" and 1 eq 2) {
writeDump("hello");
} else if (something eq "other") {
writedump("other");
}
I came across a case-switch piece of code today and was a bit surprised to see how it worked. The code was:
switch (blah)
{
case a:
break;
case b:
break;
case c:
case d:
case e:
{
/* code here */
}
break;
default :
return;
}
To my surprise in the scenario where the variable was c, the path went inside the "code here" segment. I agree there is no break at the end of the c part of the case switch, but I would have imagined it to go through default instead. When you land at a case blah: line, doesn't it check if your current value matches the particular case and only then let you in the specific segment? Otherwise what's the point of having a case?
This is called case fall-through, and is a desirable behavior. It allows you to share code between cases.
An example of how to use case fall-through behavior:
switch(blah)
{
case a:
function1();
case b:
function2();
case c:
function3();
break;
default:
break;
}
If you enter the switch when blah == a, then you will execute function1(), function2(), and function3().
If you don't want to have this behavior, you can opt out of it by including break statements.
switch(blah)
{
case a:
function1();
break;
case b:
function2();
break;
case c:
function3();
break;
default:
break;
}
The way a switch statement works is that it will (more or less) execute a goto to jump to your case label, and keep running from that point. When the execution hits a break, it leaves the switch block.
That is the correct behavior, and it is referred to as "falling through". This lets you have multiple cases handled by the same code. In advanced situations, you may want to perform some code in one case, then fall through to another case.
Contrived example:
switch(command)
{
case CMD_SAVEAS:
{
this->PromptForFilename();
} // DO NOT BREAK, we still want to save
case CMD_SAVE:
{
this->Save();
} break;
case CMD_CLOSE:
{
this->Close();
} break;
default:
break;
}
This is called a fall-through.
It is exactly doing what you are seeing: several cases is going to execute same piece of code.
It is also convenient in doing extra processing for certain case, and some shared logic:
// psuedo code:
void stopServer() {
switch (serverStatus)
case STARTING:
{
extraCleanUpForStartingServer();
// fall-thru
}
case STARTED:
{
deallocateResources();
serverStatus = STOPPED;
break;
}
case STOPPING:
case STOPPED:
default:
// ignored
break;
}
This is a typical use of fall-through in switch-case. In case of STARTING and STARTED, we need to do deallocateResources and change the status to STOPPED, but STARTING need some extra cleanup. By the above way, you can clearly present the 'common logic' plus extra logic in STARTING.
STOPPED, STOPPING and default are similar, all of them fall thru to default logic (which is ignoring).
It is not always a good way to code like this but if it is well used it can present the logic better.
Luckily for us, C++ doesn't depend on your imagination :-)
Think of the switch labels as "goto" labels, and the switch(blah) simply "goes to" the corresponding label, and then the code just flows from there.
Actually the switch statement works the way you observed. It is designed so that you can combine several cases together until a break is encountered and it acts something like a sieve.
Here is a real-world example from one of my projects:
struct keystore_entry *new_keystore(p_rsd_t rsd, enum keystore_entry_type type, const void *value, size_t size) {
struct keystore_entry *e;
e = rsd_malloc(rsd, sizeof(struct keystore_entry));
if ( !e )
return NULL;
e->type = type;
switch (e->type) {
case KE_DOUBLE:
memcpy(&e->dblval, value, sizeof(double));
break;
case KE_INTEGER:
memcpy(&e->intval, value, sizeof(int));
break;
/* NOTICE HERE */
case KE_STRING:
if ( size == 0 ) {
/* calculate the size if it's zero */
size = strlen((const char *)value);
}
case KE_VOIDPTR:
e->ptr = rsd_malloc(rsd, size);
e->size = size;
memcpy(e->ptr, value, size);
break;
/* TO HERE */
default:
return NULL;
}
return e;
}
The code for KE_STRING and KE_VOIDPTR cases is identical except for the calculation of size in case of string.