During a code review, a senior dev commented on some nesting I had going on in my code. He suggested I set a bool value so that I never have more than one level of nesting. I think my code is more readable but want to get other devs' opinion on this. Which is better style? Is his knee-jerk aversion to nesting founded?
Below are some simplified code examples.
Nested:
If(condition1)
{
If(condition2)
{
if(condition3)
{
return true;
}
else
{
log("condition3 failed");
}
else
{
log("condition2 failed")
}
}
else
{
log("condition1 failed")
}
return false;
or
Bool Driven:
bool bRC = false;
bRC = (condition1);
if(brc)
{
bRC = (condition2);
}
else
{
log("condition1 failed");
return false;
}
if(bRC)
{
bRC = (condition3);
}
else
{
log("condition2 failed");
return false;
}
if(bRC)
{
return true;
}
else
{
log("condition3 failed");
return false;
}
I like yours better, but I'd probably do something like:
if (condition1 && condition2 && condition3)
{
return true;
}
else if (!condition1)
{
log("condition1 failed");
}
else if (!condition2)
{
log("condition2 failed");
}
else
{
log("condition3 failed");
}
return false;
If the conditions are complex expressions then I might assign the expressions to appropriately named variables before evaluating the if statements to avoid having to recompute the values in each if.
This is assuming that the normal mode is that all conditions are true and thus you want to have that check first. If the normal mode is that one or more conditions are false, then I'd reorder it and check each negation in turn and simply return true if all the checks failed. That would also remove the need for temporary variables to take the place of complex expressions.
If you don't have any silly rules about multiple return points, I think this is quite nice (and so does someone else, but they deleted their answer for unknown reasons):
if(!condition1)
{
log("condition1 failed");
return false;
}
if(!condition2)
{
log("condition2 failed");
return false;
}
if(!condition3)
{
log("condition3 failed");
return false;
}
return true;
Maybe this is an equal knee-jerk aversion to super-nesting, but it's certainly cleaner than his crap storing the boolean conditions in certain values. However, it may be less readable in context: consider if one of the conditions was isreadable(). It's clearer to say if(isreadable()) because we want to know if something is readable. if(!isreadable()) suggests if we want to know whether it's not readable, which isn't our intention. It's certainly debatable that there may be situations where one is more readable/intuitive than the other, but I'm a fan of this way myself. If someone gets hung up on the returns, you could do this:
if(!condition1)
log("condition1 failed");
else if(!condition2)
log("condition2 failed");
else if(!condition3)
log("condition3 failed");
else
return true;
return false;
But that's rather underhanded, and less "clear" in my opinion.
I personally find the nested code significantly easier to read.
I generally prefer nested for my conditions; of course, if my nested conditions are getting indented too far to the right, I have to start wondering if there's a better way to go about whatever I'm trying to do (refactoring, redesigning, etc..)
Similar to the nested version, but much cleaner for me:
if not condition1:
log("condition 1 failed")
else if not condition2:
log("condition 2 failed")
else if not condition3:
log("condition 3 failed")
else
return true;
return false;
Beware that each condition is evaluated once.
The second style is absurdly verbose: did he really suggest exactly this? You don't need most of those if statements, because there is a return in the else part.
With the nested example you are relying on not forgetting to include any possible else clauses.
Neither of these seems satisfactory to me.
The bool driven way is confusing. Nesting is fine if required, but you could remove some of the nesting depth by combining the conditions into one statement, or calling a method where some of the further evaluation is done.
I think both ways are possible and have their Pros and Cons. I would use the bool-driven style in cases where i would have really deep nesting (8 or 10 or something like that). In your case with 3 levels, i would choose your style but for the exact sample from above, i would go like that:
void YourMethod(...)
{
if (condition1 && condition2 && consition3)
return true;
if (!condition 1)
log("condition 1 failed");
if (!condition 2)
log("condition 2 failed");
if (!condition 3)
log("condition 3 failed");
return result;
}
... or like that if you prefer a single exit point (like i do) ...
void YourMethod(...)
{
bool result = false;
if (condition1 && condition2 && consition3)
{
result = true;
}
else
{
if (!condition 1)
log("condition 1 failed");
if (!condition 2)
log("condition 2 failed");
if (!condition 3)
log("condition 3 failed");
}
return result;
}
That way, you will get all the failed condition logged in the first run. In your example, you will get only one failed condition logged even if there are more than one failing conditions.
I'd probably go with
if (!condition1) log("condition 1 failed");
else if (!condition2) log("condition 2 failed");
else if (!condition3) log("condition 3 failed");
// -------------------------------------------
return condition1 && condition2 && condition3;
which I believe is equivilent and much cleaner...
Also, once the client decides that all conditions should be evaluated and logged if they fail, not just the first one that fails, this is much easier to modify to do that:
if (!condition1) log("condition 1 failed");
if (!condition2) log("condition 2 failed");
if (!condition3) log("condition 3 failed");
// -------------------------------------------
return condition1 && condition2 && condition3;
This is how I would implement it, provided your implementations actually reflect the desired behavior.
if (!condition1) {
log("condition1 failed");
return false;
}
if (!condition2) {
log("condition2 failed");
return false;
}
if (!condition3) {
log("condition3 failed");
return false;
}
return true;
However, I think it's more likely that every failed condition should be logged.
result = true;
if (!condition1) {
log("condition1 failed");
result = false;
}
if (!condition2) {
log("condition2 failed");
result = false;
}
if (!condition3) {
log("condition3 failed");
result = false;
}
return result;
If the language supports exception handling, I'd go with the following:
try {
if (!condition1) {
throw "condition1 failed";
}
if (!condition2) {
throw "condition2 failed";
}
if (!condition3) {
throw "condition3 failed";
}
return true;
} catch (e) {
log(e);
return false;
}
EDIT From charles bretana: Please see Using Exceptions for control flow
I don't like either way. When you have so much nests something is wrong. In the case of a form validation or something that does indeed require something like this try to figure something out that's more modular or compact.
An example would be an array holding the conditions, through which you'll iterate with a while, and print/break as needed.
There are too many implementations depending on your needs so creating an example code would be pointless.
As a rule of thumb, when your code looks too complicated, it sucks :). Try rethinking it. Following coding practices most of the times makes the code turn out a lot more aesthetic and short; and obviously, also smarter.
Code shall restate the problem in a language given. Therefore I maintain that either snippets can be "better". It depends on the problem being modeled. Although my guess is that neither of the solutions will parallel the actual problem. If you put real terms instead of condition1,2,3 it might completely change the "best" code.
I suspect there is a better (3d) way to write that all together.
if( condition1 && condition2 && condition3 )
return true;
log(String.Format("{0} failed", !condition1 ? "condition1" : (!condition2 ? "condition2" : "condition3")));
return false;
That way, you don't have to see many lines of code just for logging. And if all your conditions are true, you don't waste time evaluating them in case you have to log.
Related
I've been trying to use and understand the DirectoryWatcher class from Microsoft's Cloud Mirror sample. It uses ReadDirectoryChangesW to monitor changes to a directory. I don't think it's reporting all changes, to be honest. In any event, I had a question about the key part of the code, which is as follows:
concurrency::task<void> DirectoryWatcher::ReadChangesAsync()
{
auto token = _cancellationTokenSource.get_token();
return concurrency::create_task([this, token]
{
while (true)
{
DWORD returned;
winrt::check_bool(ReadDirectoryChangesW(
_dir.get(),
_notify.get(),
c_bufferSize,
TRUE,
FILE_NOTIFY_CHANGE_ATTRIBUTES,
&returned,
&_overlapped,
nullptr));
DWORD transferred;
if (GetOverlappedResultEx(_dir.get(), &_overlapped, &transferred, 1000, FALSE))
{
std::list<std::wstring> result;
FILE_NOTIFY_INFORMATION* next = _notify.get();
while (next != nullptr)
{
std::wstring fullPath(_path);
fullPath.append(L"\\");
fullPath.append(std::wstring_view(next->FileName, next->FileNameLength / sizeof(wchar_t)));
result.push_back(fullPath);
if (next->NextEntryOffset)
{
next = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(reinterpret_cast<char*>(next) + next->NextEntryOffset);
}
else
{
next = nullptr;
}
}
_callback(result);
}
else if (GetLastError() != WAIT_TIMEOUT)
{
throw winrt::hresult_error(HRESULT_FROM_WIN32(GetLastError()));
}
else if (token.is_canceled())
{
wprintf(L"watcher cancel received\n");
concurrency::cancel_current_task();
return;
}
}
}, token);
}
After reviewing an answer to another question, here's what I don't understand about the code above: isn't the code potentially re-calling ReadDirectoryChangesW before the prior call has returned a result? Or is this code indeed correct? Thanks for any input.
Yes, I seem to have confirmed in my testing that there should be another while loop there around the call to GetOverlappedResultEx, similar to the sample code provided in that other answer. I think the notifications are firing properly with it.
Shouldn't there also be a call to CancelIo in there, too? Or is that not necessary for some reason?
I would like to consider one syntax improvement.
How I can write this better:
IF condition1
IF condition2
{ do something }
ELSE
{ message1 }
ELSE
{ message1 }
There are two IF statements that cannot be joined in one statement, but in both ELSE parts need to be same code (in this example message1).
How this can be written better? I wouldn't like to write same code (in ELSE parts) twice.
TnX in advance!
Nemanja
The obvious solution is to combine the two conditions:
IF condition1 AND condition2
{ do something }
ELSE
{ message1 }
However if the two conditions really can not be combined for some reason, and you are using a C-like language which has a break keyword or equivalent, then you can do something like this:
DO
IF condition1
IF condition2
{ do something }
BREAK
{ message1 }
WHILE FALSE
What about
IF condition1 AND condition2
{ do something }
ELSE
{ message1 }
If you can't join both statements, you can use some sort of GOTO (ps: this is bad practice)
IF condition1
IF condition2
{ do something }
ELSE
GOTO ELSE_CODE
ELSE
:ELSE_CODE
{ message1 }
in case you're talking about a language without short-circuit boolean evaluation, you could manually implement it like
flag = condition1
IF flag
flag = flag AND condition2
IF flag
{ do something }
ELSE
{ message1 }
I searched for this answer and I realized you just need to reorder the statements.
Instead of 2 IF statements with one else like this
{
if(FirstCheck === true){
//run function 1
}
if(SecondCheck === true){
//run function 2
}
}else{
//run this else only when the first 2 IFs are false
// run function 3
}
}
you want to do a IF for the reason why you want to run the function in the else, and then put an else for that IFs, that then runs your original IFs
if(orginalElse !== true){
//run function 3
//this is the orginal else you would want to run, just with a negative if statement
}else{
if(FirstCheck === true){
//run function 1
}
if(SecondCheck === true){
//run function 2
}
}
I am trying to submit data to a server where it is picked and stored in salesforce. The error I am getting is "Attempt to de-reference a null object" at the server. so I am wondering what the problem is...
Below is the sample code:
public static List<String> processAgentVisitSurvey(ProcessSurveySubmission.SurveySubmission submission, Map<String, Submission_Answer__c> answers, Person__c person) {
// Load the TDR
TDR__c tdr = loadTdr(person);
if (tdr == null) {
//Send an email saying that an unregistered person is trying to act a TDR
// Send back the error message
return new String[] { '0', 'User with handset Id ' + submission.imei + ' is not a TDR', 'SUPRESSMSG' };
}
This is the source of the error message.
There is a class the redirects to this method:
private static List<String> additionalProcessing(
SurveySubmission surveySubmission,
Survey__c survey,
Person__c interviewer,
Id intervieweeId
) {
List<String> returnValues = new List<String>();
Map<String, Submission_Answer__c> answers = parseSubmissionToMap(surveySubmission);
// Find the name of the method that this survey hooks into to do its post processing
try {
if (survey.Post_Processing_Method__c.equalsIgnoreCase('None')) {
returnValues.add('0');
returnValues.add('There is no post processing method specified for this survey');
returnValues.add('SUPRESSMSG');
}
else if (survey.Post_Processing_Method__c.equals('CKW_Registration')) {
return CkwRegistration.processCkwRegistration(answers, interviewer);
}
else if (survey.Post_Processing_Method__c.equals('CKW_Baseline')) {
return CkwRegistration.processCkwBaseline(answers, interviewer);
}
else if (survey.Post_Processing_Method__c.equals('CKW_Staff_Update')) {
return CkwRegistration.processCkwUpdate(answers, interviewer);
}
else if (survey.Post_Processing_Method__c.equals('Subcounty_Registration')) {
return CkwRegistration.processSubcounties(answers, interviewer);
}
else if (survey.Post_Processing_Method__c.equals('TDR_AGENT_VISIT')) {
return TdrHelpers.processAgentVisitSurvey(surveySubmission, answers, interviewer);
}
else if (survey.Post_Processing_Method__c.equals('UDOM_RAIN_GUAGE')) {
return UDoMSurveyProcessing.processDailyRainGauge(surveySubmission, answers, interviewer);
}
else if (survey.Post_Processing_Method__c.equals('UDOM_RAIN_GUAGE_REG')) {
return UDoMSurveyProcessing.registerRainGauge(surveySubmission, answers, interviewer);
}
else if (survey.Post_Processing_Method__c.equals('MTN_CHANNELS')) {
return MtnChannelsHelpers.processChannelsFFPSSurvey(surveySubmission, answers, interviewer);
}
else if (survey.Post_Processing_Method__c.equals('FHI_GROUP_REGISTRATION')) {
return FHISurveysHelpers.processGroupRegistration(surveySubmission, answers, interviewer, survey.Survey_Name__c);
}
else if (survey.Post_Processing_Method__c.equals('FHI_HOUSEHOLD_REGISTRATION')) {
return FHISurveysHelpers.processHouseholdRegistration(surveySubmission, answers, interviewer, survey.Survey_Name__c);
}
// else if (survey.Post_Processing_Method__c.equals('Colombia_Farmer_Registration')) {
// return ColombiaFarmerRegistrationPostProcessor.processSubmission(surveySubmission, answers, interviewer);
// }
else if (survey.Post_Processing_Method__c.equals('FIELD_OFFICER_SUPPORT')) {
return FieldOfficeHelpers.processFoSurvey(surveySubmission, answers, interviewer);
}
// else if (survey.Post_Processing_Method__c.equals('DATA_VALIDATOR_SPOT_CHECK')) {
// return DataValidatorHelpers.processSpotCheck(surveySubmission, answers, interviewer);
// }
// else if (survey.Post_Processing_Method__c.equals('DATA_VALIDATOR_BACK_CHECK')) {
// return DataValidatorHelpers.processBackCheck(surveySubmission, answers, interviewer);
// }
else if (survey.Post_Processing_Method__c.equals('EQUIPMENT_TRACKING')) {
return EquipmentTrackingHelpers.processFieldOfficerSubmission(surveySubmission, answers, interviewer);
}
}
catch (Exception e) {
returnValues.add('0');
returnValues.add(e.getMessage());
returnValues.add('An error occured. Please contact support');
}
return returnValues;
}
which I think is fine...
Please help coz I do not seem to see any problem
Thank you. I hope the code provide is enough.
Usually when I run across that error my first instinct is to look for any queries. In APEX when you return a null value (expected or not) into a single item such as Person__c person = [query that returns objects}; that error is thrown.
The SOLUTION is to ensure data gets returned into a concrete SObject such as...
List<Person__c> persons = [Here is a query or method call];
Then you would check the list with persons.size() This obeys salesforce's Bulkify everything approach they enforce as well as a more robust backend.
Sorry I couldn't provide more support, the error wasn't very evident in your code samples without a line number or debug log.
Good Luck!
Be aware: This error can also appear if you are trying to reference an uninstantiated property of a class.
Example: If you declare a List property of a class, but never instantiate it, and then attempt to add to that list, you will get this error.
What would be the best way to write an algorith like:
if (a) {
doA();
done();
}
else if (b) {
doB();
done();
}
else if (c) {
doC();
done();
}
another approach I thought:
done = true;
if (a) {
doA();
}
else if (b) {
doB();
}
else if (c) {
doC();
}
else {
done = false;
}
if (done) {
done();
}
Which is better? Is there another best approach?
Without any context, the most natural looking way for me is:
bool do_it(int condition)
{
switch (condition)
{
case a: doA(); return true;
case b: doB(); return true;
case c: doC(); return true;
default: return false;
}
}
// ...
if (do_it) done();
since it abstracts the logic of "if this whole stuff succeeds, then do call done()".
But there are many other ways to do this. Especially, if the number of conditions will likely grow in the future, I wouldn't do that at all.
Depends on how many conditions/actions are there and kind of language you are using.
OOP and polymorphysm could work nicely.
Use a switch statement, setting an isDone flag along the way, and call done() based on the flag.
If a,b and c are different complex conditional expressions then your first solution is the best. Maybe you can avoid the "else if" elements if this code is inside a function, like that:
private void doit() {
if (a) {
doA();
done();
return;
}
if (b) {
doB();
done();
return;
}
if (c) {
doC();
done();
return;
}
}
So for me it is much more a code style question.
I would write it as
var failed = false;
if (a) doA();
else if (b) doB();
else if (c) doC();
else failed = true;
if (!failed) done();
I don't like setting a variable like done first to true and later undoing it, because the work is not done before the conditional starts, so it looks illogical.
I also don't like the switch case option because the conditions 'a', 'b', 'c' are not necessarily mutually exclusive; the if ... else if ... else cascade supports non-exclusive conditions but switch() might not depending on the language. E.g. you can't convert cascading if ... else's to switch in C++.
I think it's definitely important to remove multiple call points to done() because that's redundancy and later a maintenance issue if done() e.g. gets parameters.
First, have one condition variable, not three. Second, I'd use a map of function pointers, with the condition variable as the key. Here's an example:
#!/usr/bin/env python
def doA():
pass
def doB():
pass
def doC():
pass
def done():
pass
a = 3
b = 6
c = 8
doers = {}
doers[a] = doA
doers[b] = doB
doers[c] = doC
condition = a
# this is now the entire "algorithm":
if condition in doers:
doers[condition]()
done()
This is related to a chapter from beautiful code.
And in that chapter I read about the nested ifs.
The author was talking about deeply nested ifs as originator of bugs and less readable.
And he was talking about replacing nested ifs with case statements and decision tables.
Can anybody illustrate how to remove nested ifs with case (select case) and decision tables ?
Well, not directly an answer to your question since you specifically ask about switch/case statements, but here is a similar question.
Invert “if” statement to reduce nesting
This talks about replacing nested if's with guard-statements, that return early, instead of progressively checking more and more things before settling on a return value.
One example I always try to do is replace heavily nested if's like this (actually this one's not too bad but I've seen them up to 8 or 9 levels deep in the wild):
if (i == 1) {
// action 1
} else {
if (i == 2) {
// action 2
} else {
if (i == 3) {
// action 3
} else {
// action 4
}
}
}
with this:
switch (i) {
case 1:
// action 1
break;
case 2:
// action 2
break;
case 3:
// action 3
break;
default:
// action 4
break;
}
I also try to keep the actions as small as possible (function calls are best for this) to keep the switch statement compressed (so you don't have to go four pages ahead to see the end of it).
Decision tables, I believe, are simply setting flags indicating what actions have to be taken later on. The "later on" section is simple sequencing of actions based on those flags. I could be wrong (it won't be the first or last time :-).
An example would be (the flag-setting phase can be complicated if's since its actions are very simple):
switch (i) {
case 1:
outmsg = "no paper";
genmsg = true;
mailmsg = true;
phonemsg = false;
break;
case 2:
outmsg = "no ink";
genmsg = true;
mailmsg = true;
phonemsg = false;
break;
default:
outmsg = "unknown problem";
genmsg = true;
mailmsg = true;
phonemsg = true;
break;
}
if (genmsg)
// Send message to screen.
if (mailmsg)
// Send message to operators email address.
if (phonemsg)
// Hassle operators mobile phone.
How about chained ifs?
Replace
if (condition1)
{
do1
}
else
{
if (condition2)
{
do2
}
else (condition3)
{
do3;
}
}
with
if (condition1) {
do1;
} else if (condition2) {
do2;
} else if (condition3) {
do3;
}
This is much like switch statement for complex conditions.
Make the condition into booleans and then write boolean expression for each case.
If the code was:
if (condition1)
{
do1
}
else
{
if (condition2)
{
do2
}
else (condition3)
{
do3;
}
}
One can write it as:
bool cond1=condition1;
bool cond2=condition2;
bool cond3=condition3;
if (cond1) {do1;}
if (!cond1 and cond2) {do2;}
if (!cond1 and cond3) {do2;}
For decision tables, please see my answer to this question, or better still read chapter 18 in Code Complete 2.
You can just break once a part of the validation failed for example.
function validate(){
if(b=="" || b==null){
alert("Please enter your city");
return false;
}
if(a=="" || a==null){
alert("Please enter your address");
return false;
}
return true;
}
Decision tables are where you store the conditional logic in a data structure rather than within the code itself.
So instead of this (using #Pax's example):
if (i == 1) {
// action 1
} else {
if (i == 2) {
// action 2
} else {
if (i == 3) {
// action 3
} else {
// action 4
}
}
}
you do something like this:
void action1()
{
// action 1
}
void action2()
{
// action 2
}
void action3()
{
// action 3
}
void action4()
{
// action 4
}
#define NUM_ACTIONS 4
// Create array of function pointers for each allowed value of i
void (*actions[NUM_ACTIONS])() = { NULL, action1, action2, action3 }
// And now in the body of a function somewhere...
if ((i < NUM_ACTIONS) && actions[i])
actions[i]();
else
action4();
If the possibilities for i are not low-numbered integers then you could create a lookup table instead of directly accessing the ith element of the actions array.
This technique becomes much more useful than nested ifs or switch statements when you have a decision over dozens of possible values.
If and switch statements are not purely OO. They are conditional procedural logic, but do a very good job! If you want to remove these statements for a more OO approach, combine the 'State' and 'Descriptor' patterns.
You might also consider using the Visitor pattern.
Nested if are equivalent to the logical operator AND
if (condition1)
{
if (function(2))
{
if (condition3)
{
// do something
}
}
}
Equivalent code:
if (condition1 && function(2) && condition3)
{
// do something
}
In both cases, when an expression evaluates false, the subsequent expression will not be evaluated. For example, if condition1 is false, the function() will not be called, and condition3 won't be evaluated.
Another example some languages allow is this
switch true{
case i==0
//action
break
case j==2
//action
break
case i>j
//action
break
}