Exception Handling with Multiple Variables - if-statement

I'm trying to learn more about exception handling while working on my program. I have multiple test variables I want to test and make sure it is within range with:
public bool IsWithinRange(TextBox textbox, string name, int min, int max)
{
double number = double.Parse(textbox.Text);
if (number < min || number > max)
{
MessageBox.Show(name + " must be between " + min.ToString() + " and " + max.ToString() + ".", "Entry Error");
textbox.Focus();
return false;
}
else { return true; }
}
And calling the method using:
bool condition;
condition = CheckAll();
if (condition == true) { condition = IsWithinRange(txtVar1, "Var1", 1, 50); }
if (condition == true) { condition = IsWithinRange(txtVar2, "Var2", -100, 100); }
if (condition == true) { condition = IsWithinRange(txtVar3, "Var3", 100, 200); }
This logic works, but I was curious to see if there was a more concise, better looking way of writing some form of systematic checking of variables one by one?

You can take advantage of a few things:
Are you able to assign meaningful names to the TextBox.Name properties? If so, you can omit the second parameter in "IsWithinRange" and simply call "Textbox.Name".
As of C# 6.0, there is now a syntax to interpolate strings. So the string passed into your your MessageBox.Show syntax can be made shorter and prettier.
You can immediately assign to "condition", and you can convert your "if" statements to combined "and" statements.
All together, your code can look like this:
bool condition =
CheckAll()
&& IsWithinRange(txtVar1, 1, 50)
&& IsWithinRange(txtVar2, -100, 100)
&& IsWithinRange(txtVar3, 100, 200);
// Some other code here
With your method looking like this:
public bool IsWithinRange(TextBox textbox, int min, int max) {
double number = double.Parse(textbox.Text);
if (number < min || number > max) {
MessageBox.Show($"{textbox.Name} must be between {min} and {max}.", "Entry Error");
textbox.Focus();
return false;
}
else
return true;
}
This is assuming you actually use "condition". If not, you can omit "bool condition = " and the code runs just the same.
But there are a few things to note. Your code will continue to run even if "CheckAll" is false or any "IsWithinRange" is false. This is true in my version above or in your own version. Yes, your user will get a message, but after he clicks "okay", the remaining code will run even if the checks fail.
Also, "IsWithinRange" might be misinterpreted by a teammate or even by yourself in the future. This is because it does more than just return true/false: it sends a message if false. This violates the principle of command-query separation.
An approach to these issues ignores brevity, as that is desired but never the highest goal. What you can do is create a class that validates, whose methods separate the tasks:
class Validator {
public bool isValid = true;
public List<string> messages = new List<string>();
public Validator CheckAll() {
// Whatever your logic is for this.
return this; // Return the instance of "Validator" that called this method
}
public Validator CheckRange (TextBox textbox, int min, int max) {
double number = double.Parse(textbox.Text);
if (number < min || number > max) {
messages.Add($"{textbox.Name} must be between {min} and {max}.");
isValid = false;
}
return this;
}
public void ShowErrorsToUser () =>
MessageBox.Show(string.Join(Environment.NewLine, messages));
}
Which you would use like this:
var validator =
new Validator()
.CheckAll()
.CheckRange(txtVar1, 1, 50)
.CheckRange(txtVar2, -100, 100)
.CheckRange(txtVar3, 100, 200);
if (!validator.isValid) {
validator.ShowErrorsToUser();
txtVar1.Focus();
return; // Stop code execution!
}
// Continue with your normal logic that utilizes your textbox values.
I'll leave it to you to decide whether the class-based approach is worth your time. But I present it to you as a different way to think.

Related

Recursive symbol checking

I am getting an error that I am having problems fixing as recursion hasn't "sunk in" yet.
It is supposed to go through an array of symbols already placed by the Class OrderManager Object and check if the symbol passed in is already there or not, if it is not there it should allow the trade, otherwise it will block it (multiple orders on the same currency compounds risk)
[Error] '}' - not all control paths return a value.
I believe it is because of the retest portion not having a return value but again I'm still newish to making my own recursive functions. However it may also be because my base and test cases are wrong possibly?
P.S I added (SE) comments in places to clarify language specific things since it is so close to C++.
P.P.S Due to the compiler error, I have no clue if this meets MVRC. Sorry everyone.
bool OrderManager::Check_Risk(const string symbol, uint iter = 0) {
if((iter + 1) != ArraySize(m_symbols) &&
m_trade_restrict != LEVEL_LOW) // Index is one less than Size (SE if
// m_trade_restrict is set to LOW, it
// allows all trades so just break out)
{
if(OrderSelect(OrderManager::Get(m_orders[iter]),
SELECT_BY_TICKET)) // Check the current iterator position
// order (SE OrderSelect() sets an
// external variable in the terminal,
// sort of like an environment var)
{
string t_base = SymbolInfoString(
OrderSymbol(),
SYMBOL_CURRENCY_BASE); // Test base (SE function pulls apart
// the Symbol into two strings
// representing the currency to check
// against)
string t_profit =
SymbolInfoString(OrderSymbol(), SYMBOL_CURRENCY_PROFIT);
string c_base =
SymbolInfoString(symbol, SYMBOL_CURRENCY_BASE); // Current base
// (SE does the same as above but for the passed variable instead):
string c_profit = SymbolInfoString(symbol, SYMBOL_CURRENCY_PROFIT);
// Uses ENUM_LEVELS from Helpers.mqh (SE ENUM of 5 levels: Strict,
// High, Normal, Low, None in that order):
switch(m_trade_restrict) {
case LEVEL_STRICT: {
if(t_base == c_base || t_profit == c_profit) {
return false; // Restrictions won't allow doubling
// orders on any currency
} else
return Check_Risk(symbol, iter++);
};
case LEVEL_NORMAL: {
if(symbol == OrderSymbol()) {
return false; // Restrictions won't allow doubling
// orders on that curr pair
} else
return Check_Risk(symbol, iter++);
};
default: {
// TODO: Logging Manager
// Hardcoded constant global (SE set to LEVEL_NORMAL):
ENB_Trade_Restrictions(default_level);
return Check_Risk(symbol, iter);
}
}
}
} else {
return true;
}
}
So, I must just have been staring at the code for too long but the problem was the if(OrderSelect(...)) on ln 7 did not have a return case if the order was not properly set in the terminal. I will need to polish this but the following code removes the error.
bool OrderManager::Check_Risk(const string symbol, uint iter=0)
{
if((iter + 1) != ArraySize(m_symbols) && m_trade_restrict != LEVEL_LOW) // Index is one less than Size
{
if(OrderSelect(OrderManager::Get(m_orders[iter]), SELECT_BY_TICKET)) //Check the current iterator position order
{
string t_base = SymbolInfoString(OrderSymbol(), SYMBOL_CURRENCY_BASE); //Test base
string t_profit = SymbolInfoString(OrderSymbol(), SYMBOL_CURRENCY_PROFIT);
string c_base = SymbolInfoString(symbol, SYMBOL_CURRENCY_BASE); //Current base
string c_profit = SymbolInfoString(symbol, SYMBOL_CURRENCY_PROFIT);
switch(m_trade_restrict) // Uses ENUM_LEVELS from Helpers.mqh
{
case LEVEL_STRICT :
{
if(t_base == c_base || t_profit == c_profit)
{
return false;
}
else return Check_Risk(symbol, ++iter);
};
case LEVEL_NORMAL :
{
if(symbol == OrderSymbol())
{
return false;
}
else return Check_Risk(symbol, ++iter);
};
default: {
// TODO: Logging Messages
ENB_Trade_Restrictions(default_level); //Hardcoded constant global
return Check_Risk(symbol, iter);
}
}
}
else {return Check_Risk(symbol, ++iter);}
}
else {return true;}
}

how to check if personID is in my_customers (see my example)

In C++, the interface for this file says
*If no soup left returns OUT_OF_SOUP
* If personID not found in my_customers AND numbBowlsSoupLeft>0 then give this person a bowl of soup (return BOWL_OF_SOUP)
* and record it by creating new customer struct using personID, numbBowlsSoup=1 and adding this struct to my_customers, be sure to decrement numbBowlsSoupLeft.
for my implementation, I'm trying to put
int Soupline::getSoup(int personID) {
if (numBowlsSoupLeft == 0) {
return OUT_OF_SOUP;
}
if (!(personID : my_customers) && numbBowlsSoupLeft > 0) {
}
But that second if statement is giving me syntax errros, I just want to know how to check to see if the personID is IN my_customers?
my_customers was created in the soupline interface using:
std::vector<customer> my_customers; // keeps track of customers
First you want to use find() to search a vector.
Second, please handle the case if numbBowlsSoupLeft < 0, because that can be a huge source of problem.
Third, your syntax error is the (personID : my_customers), the : is for iteration.
int Soupline::getSoup(int personID) {
if (numBowlsSoupLeft <= 0) { // handles negative numBowlsSoupLeft
return OUT_OF_SOUP;
}
bool found_customer = false;
for (auto c : my_customers) {
if (personID == c.person_id()) { // This is my guess on how the id is stored in customer class
// Logic to process soup for customer
found_customer = true;
break;
}
}
if (!found_customer) {
// Logic to process non-customer asking for soup?
}
}
Sorry i dunno what is the return integer is supposed to be, so it is not defined in my code example.

Is it good practice to have boolean "recursiveCall" parameter in a function?

I have a function which calls itself, but to avoid infinite recursion when the function is calling itself I pass a boolean variable so it does not call itself again. However this also means someone using my code can use the function and pass it a true argument.
class Test
{
public:
static bool doCheck(int x, bool recursiveCall = false)
private:
int m_array {10, 5, 3, 25, 12, 0, -6};
int tracker = 0;
};
bool Test::doCheck(int x, bool recursiveCall)
{
if (m_array[tracker] > x)
{
//do stuff
++tracker;
return true;
}
else if (!recursiveCall)
{
// reset tracker
tracker = 0;
return doCheck(x, true);
}
return false;
}
int main()
{
Test::doCheck(2); // returns true, m_array[tracker] now equals 5
// The next call will go through the "else if" part which will reset the tracker
// and return false, if we didn't call the function as recursive it would call itself infinitely !
Test::doCheck(50);
return 0;
}
Edit: As requested I provided a better example. Of course we could perform the m_array[tracker] > x before calling doCheck() again but it means our check will be done twice, and it can be problematic if we check some things using a more complex algorithm
Is it good practice to do that?
No, that's a bad idea. Instead re-write your base case so that it will always stop on it's own.
Your example is never going to sensibly recurse, so it may as well be
void foo(int x)
{
if (x > 10)
{ /* Do stuff here */ }
}

C++, Adding conditions in class vars

The title may not be right because I can't find an appropriate words for it.
I want to add conditions to some object (instance created by class).
In obj.h: (excluding preprocessor commands)
class obj {
public:
void addCondition( bool cond );
void useCondition();
private:
bool conditions;
};
In obj.cpp: (excluding preprocessor commands)
void obj::addCondition( bool cond )
{
//What to write here, is the question in short!!!
}
void obj::useCondition()
{
if(conditions)
{
//Do something...
}
}
Suppose that the conditions was:
conditions = value1 > value2;
I wanted to 'ADD' a condition in conditions so, that it becomes something like that:
conditions = (value1 > value2) || (value3 <= value4);
OR
conditions = (value 1 > value2) && (value3 <= value4);
If I am wrong about something in asking things, I am sorry! If you know something other than the answer but the whole different thing that does the same thing, don't hesitate to discuss it.
Thanks in advance!
I assume you know why conditions field and condition parameter are both simple boolean variables. If that is true, it could be very simple, but you should replace addCondition with andCondition and orCondition :
void obj::andCondition( bool cond )
{
conditions = conditions && condition;
}
void obj::orCondition( bool cond )
{
conditions = conditions || condition;
}
And you should define whether conditions is initialy true or false. You can always set it to a defined value, because with code above :
obj.andCondition(false);
sets conditions to false, and
obj.orCondition(true);
sets conditions to true
Edit per comments:
The above answer is based on the requirement that conditions is a simple boolean variable, and condition is a simple boolean value.
Here is one example of what could be done if you want to re-evaluate the condition.
A class and-ing (resp. or-ing) conditions represented by boolean variables evaluated at the moment where useCondition is used :
class andcond {
std::list<bool *> conditions;
public:
void addCondition(bool &condition) {
conditions.push_back(&condition);
}
bool isCondition();
};
bool andcond::isCondition() {
bool retval = true;
for (std::list<bool *>::iterator it = conditions.begin(); it != conditions.end(); it++) {
retval = retval && **it;
}
return retval;
}
int main() {
bool a=false, b=true;
andcond c;
c.addCondition(a);
c.addCondition(b);
std::cout << c.isCondition() << std::endl; // is false here
a = true;
std::cout << c.isCondition() << std::endl; // is true here
return 0;
}
Note : conditions is a list of pointers to boolean variables that can be re-evaluated
You could even be more genereral by defining a full hierarchy of condition classes implementing a bool eval() method, for example the equality or inequality between 2 variables, and combinable by and and or. But it is way too complex for a disgression on an initial answer on SO. But you can try to implement this idea and ask more precise questions here when stuck ...

What's a graceful way of doing an "if none of the above"?

I'm sure you've been there. You want to say "if flib do this, if flob do that, if flab do diet, etc" where any number of them can be true, then at the end you want an "if you didn't do ANY of them".
For example (the examples below are in Swift, as I've been playing with it, but I think the situation is the same in most languages):
let thing = 101
var isInteresting = false
if (thing % 3 == 0) {
println("\"\(thing)\" is a multiple of three.")
isInteresting = true
}
if (thing > 100) {
println("\"\(thing)\" is greater than one hundred.")
isInteresting = true
}
if (thing > 1000) {
println("\"\(thing)\" is greater than one thousand.")
isInteresting = true
}
if !isInteresting {
println("\"\(thing)\" is boring.")
}
I find keeping track of a boolean to tell me whether I did anything or not kinda ungainly.
The only other way I came up with was this:
let thing = 101
let isAMultipleOfThree = (thing % 3 == 0)
let isGreaterThan100 = (thing > 100)
let isGreaterThan1000 = (thing > 1000)
if isAMultipleOfThree {
println("\"\(thing)\" is a multiple of three.")
}
if isGreaterThan100 {
println("\"\(thing)\" is greater than one hundred.")
}
if isGreaterThan1000 {
println("\"\(thing)\" is greater than one thousand.")
}
if !(isAMultipleOfThree || isGreaterThan100 || isGreaterThan1000 ) {
println("\"\(thing)\" is boring.")
}
but if anything that's worse (if you add a new clause you need to remember to add it in three places.
So my question is, is there a neat, succinct way of doing this?
I'm dreaming of an imaginary switch-like statement:
switchif { //Would have fallthrough where every case condition is checked
case thing % 3 == 0:
println("\"\(thing)\" is a multiple of three.")
case thing >100 :
println("\"\(thing)\" is greater than one hundred.")
case thing > 1000:
println("\"\(thing)\" is greater than one thousand.")
none: //Unlike 'default' this would only occur if none of the above did
println("\"\(thing)\" is boring.")
}
It's a good question that does not have a perfect answer. However, here's one other idea in addition to those you suggest: Encapsulate the testing machinery in a procedure to allow the calling code at least to be a bit more streamlined.
Specifically, for your example, the calling code can be this:
if (! doInterestingStuff(101)) {
println("\"\(thing)\" is boring.");
}
If testing is encapsulated into a procedure:
public boolean doInterestingStuff(int thing) {
var isInteresting = false
if (thing % 3 == 0) {
println("\"\(thing)\" is a multiple of three.")
isInteresting = true
}
if (thing > 100) {
println("\"\(thing)\" is greater than one hundred.")
isInteresting = true
}
if (thing > 1000) {
println("\"\(thing)\" is greater than one thousand.")
isInteresting = true
}
return isInteresting
}
I'm not sure how you'd do this in Swift, but since you didn't give a language tag I'll answer in C++.
The key to this is that && is short circuiting, and the second part won't be evaluated when the first part is false. It's the same idea as your boolean flag, but it's a little more automated.
struct Tracker
{
Tracker() : any(false) { }
bool operator()() { any = true; return true; }
bool any;
};
int thing = 101;
Tracker tracker;
if (thing % 3 == 0 && tracker()) {
printf("\"%d\" is a multiple of three.\n", thing);
}
if (thing > 100 && tracker()) {
printf("\"%d\" is greater than one hundred.\n", thing);
}
if (thing > 1000 && tracker()) {
printf("\"%d\" is greater than one thousand.\n", thing);
}
if (!tracker.any) {
printf("\"%d\" is boring.\n", thing);
}
See it in action: http://ideone.com/6MQYY2
kjhughes' answer inspired me a little:
Perhaps one could write a global function that accepts an indeterminate number of key-value pairs (or even just two element arrays), where the key is a comparison and the value is the statement to run if it's true. Then return false if none of them were run, otherwise true.
Update:
Tried it, it's horrible!
//Function:
func ifNone(ifNoneFunc:()->Void, tests: Bool...)
{
var oneTestPassed = false
for test in tests
{
oneTestPassed |= test
}
if(!oneTestPassed)
{
ifNoneFunc()
}
}
//Example:
let thisThing = 7
ifNone(
{
println("\(thisThing) is boring")
},
{
if(thisThing % 10 == 0)
{
println("\"\(thisThing)\" is a multiple of 10")
return true
}
else
{
return false
}
}(),
{
if(thisThing % 3 == 0)
{
println("\"\(thisThing)\" is a multiple of 3")
return true
}
else
{
return false
}
}(),
{
if(thisThing > 1_000_000)
{
println("\"\(thisThing)\" is over a million!!")
return true
}
else
{
return false
}
}()
)