Consider the following code:
// this method should add numbers, the requirements are:
// x >= 3 and y <= 5
int add(int x, int y)
{
if(x < 3) throw new ...;
if(y > 5) throw new ...;
}
It's absolutely traditional approach, but in case you pass invalid values for both x and y, you'll only get an exception for x. Why x and not y? Just because you first check x and only then y. Why? That's basically the main question.
In the code above, there's absolutely no sense in checking x before y or y before x. Just because the idea of execution flow in a single thread, some statements are executed before others.
I'm thinking about implementing a mechanism for working with parallel exceptions. The idea is, if there are 2 statements that can be executed simultaneously (execution order doesn't matter) and both of them throw exceptions, I'd like to be able to handle all these exception. The pseudo-code is like following:
// this method should add numbers, the requirements are:
// x >= 3 and y <= 5
int add(int x, int y)
{
parallel
{
if(x < 3) throw new ...;
if(y > 5) throw new ...;
} // point A
return x + y;
}
Somewhere at point A the cumulative exception is thrown. Have you ever seen this approach before, or may be even implemented something of that kind? The main goal here is that if you have a complicated operation, that uses a number of another operation, and the "topmost" operation fails for some reason, you're able to get full diagnostics for what was wrong: not a single error (or a number of nested errors), but a tree of errors.
The questions are:
What do you think?
Have you seen it before?
Have you tried implementing something similar?
Perhaps use an AggregateException?
You seem to want to enforce a set of business rules.
One approach is to create a collection of broken rules and add specific broken rules (e.g. input too short, input must be alphanumeric) as separate elements of that collection, then throw a BrokenRulesException that includes the collection of broken rules as a parameter.
That allows the caller to fully understand what's wrong with the input without changing any language semantics.
Whats wrong with:
int add(int x, int y)
{
if(x < 3 || y > 5)
throw new Error("Incorrect Parameter, x must be >= 3 and y must be <= 5");
}
I think that this would be extraordinarily difficult without implementing something called a continuation -- the ability to return the current state of a function for delayed execution.
Basically, the problem is that instead of an exception (or, rather, a thrown... thing as you do not always have to throw an Exception object in all languages) being a message that a point which cannot be handled has been reached, it would have to return both that and the ability to force continuation past that point anyway. (Thus, you would need continuations)
Additionally, at least on the lower level, this would force the language to always throw an object in those cases. Throwing an int, on the other hand, is occasionally useful.
All of that said, there is nothing stopping you from, say, implementing a macro which works similar to how you've described.
// this method should add numbers, the requirements are:
// x >= 3 and y <= 5
int add(int x, int y)
{
if(x < 3 && y > 5) throw new ...;
if(x < 3) throw new ...;
if(y > 5) throw new ...;
}
Can't this be fairly easily done, without the need for AggregateExceptions or similar:
string ErrorMessage="";
if(x<3) ErrorMessage += "x must be >=3\n";
if(y>5) ErrorMessage += "y must be <=5\n";
if(ErrorMessage!="") throw new Exception(ErrorMessage);
if a string is too simple, it's easy to do something similar with a more complex object type.
Related
Assume we have a huge list of numeric cartesian coordinates (5;3)(1;-9) etc. To represent a point in oop I created a struct/object (c#):
public struct Point
{
public int X, Y { get; }
public Point(int x, int y)
{
// Check if x,y falls within certain boundaries (ex. -1000, 1000)
}
}
It might be wrong of how I am using struct. I guess normally you would not use a constructor but this is not the point.
Suppose I want to add a list of 1000 points and there is no guarantee that these coordinates fall within boundaries. Simply if the point is not valid, move to the next one without failing and inform user about it. As for object, I would think that Point should be responsible for instantiation and validation by itself but I am not sure how to deal with it in this particular case. Checking x, y beforehand by the caller would be the simplest approach but it does not feel right because caller would have to handle logic that should reside in Point.
What would the most appropriate approach to validate and handle incorrect coordinates without failing and violating SRP?
You can't do this in the constructor; the constructor either runs succesfully or it doesn't. If it doesn't its because an exception is raised, so, so much for silently failing. You could catch exceptions but that woul basically mean you are using exceptions as a control flow mechanism and that is a big no no, don't do that!
One solution similar to what you are thinking is to use a static factory method:
public struct Point
{
public static bool TryCreatePoint(int x, int y, Bounds bounds, out Point point)
{
if (x and y are inside bounds)
{
point = new Point(x, y);
return true;
}
point = default(Point);
return false;
}
//...
}
And the code adding points to the list should act based upon creation success.
Fun fact: if you are using C# 7 the code could look a lot cleaner:
public static (bool Succesful, Point NewPoint) TryCreatePoint(int x, int y, Bounds bounds)
{
if (x and y are inside bounds)
return (true, new Point(x, y));
return (false, default(Point));
}
I can think of three options:
Have the constructor throw an exception that you catch. This is not really great if you are expecting a lot of failures.
Have an IsValid property on the struct that you can use to filter it out once created.
Have the thing loading the data take responsibility for validating the data as well. This would be my preferred option. You say "it does not feel right because caller would have to handle logic that should reside in Point" but I would argue that the responsibility for checking that loaded data is correct is with the thing loading the data, not the data type. You could also have it throw an ArgumentOutOfRangeException in the constructor if the inputs are not valid now that you are no longer expecting anything invalid to be passed as a belt and bracers approach to things.
What you want to do is simply not posible, an instance of a class is either fully created or not at all. If the constructor has been called the only way to not instantiate an instance is by throwing an exception.
So you have these two opportunities to do this:
Extract a method Validate that returns a bool and can be called from the caller of your class.
public struct Point
{
public int X, Y { get; }
public Point(int x, int y)
{
}
}
public bool Validate() { return -1000 <= X && X <= 1000 && -1000 <= Y and Y <= 1000; }
Of course you could do the same using a property.
Throw an exception in the constructor
public Point(int x, int y)
{
if(x > 1000) throw new ArgumentException("Value must be smaller 1000");
// ...
}
However the best solution IMHO is to validate the input before you even think about creating a point, that is check the arguments passed to the constructor beforehand:
if(...)
p = new Point(x, y);
else
...
To be honest, Point shouldn't check boundaries, so the caller should do that. A point is valid in the range that their X and Y can operate (int.MinValue and int.MaxValue). So a -1000000,2000000 is a valid point. The problem is that this point isn't valid for YOUR application, so YOUR application (the caller), the one who is using point, should have that logic, not inside the point constructor.
Structs in C# are funny so I'll add another "funny" way to check:
struct Point
{
int _x;
public int X
{
get { return _x; }
set { _x = value; ForceValidate(); }
} // simple getter & setter for X
int _y;
public int Y
{
get { return _y; }
set { _y = value; ForceValidate(); }
} // simple getter & setter for Y
void ForceValidate()
{
const MAX = 1000;
const MIN = -1000;
if(this.X >= MIN && this.X <= MAX && this.Y >= MIN && this.Y <= MAX)
{
return;
}
this = default(Point); // Yes you can reasign "this" in structs using C#
}
}
I have a class,
public class NullsAreLast : IComparer<int?>
{
public int Compare (int? x, int? y)
{
if(y == null)
return -1;
else if(x == null)
return 1;
else
return (int)x - (int)y;
}
}
which is self-explanatory on how it is supposed to work.
Whenever I run
arr.OrderBy(i => i, new NullsAreLast())
with at least two null values in arr it runs forever! Any idea why?
Keep in mind that a sorting algorithm may compare the same two values several times over the process of ordering the whole sequence. Because of this, it's very important to be aware of all three possible results: less than, greater than, and equal.
This is (mostly) fine for your integer comparison at the end (the subtraction operation). There are some weird/rare edge cases when working with floating point numbers instead of integers, and calling .CompareTo() is the preferred practice anyway, but subtraction is usually good enough in this case. However, the null checks here are a real problem.
Think about what happens as a list is nearly finished sorting. You have two null values that have both made their way to the front of the list; the algorithm just needs to verify they are in the correct position. Because both x and y are null, your function should return 0. They are equivalent (for this purpose, at least). Instead, the code always returns -1. The y value will always be less than then x value, and so the algorithm will always believe it still needs to swap them. It swaps, and tries to do the same thing again. And again. And again. And again. It can never finish.
Try this instead:
public class NullsAreLast : IComparer<int?>
{
public int Compare (int? x, int? y)
{
if(!y.HasValue)
{
if (!x.HasValue) return 0;
return -1;
}
if(!x.HasValue) return 1;
return x.Value.CompareTo(y.Value);
}
}
The minus operation at the end of your Compare method isn't appropriate for comparison. You need to handle exactly three possibilities - x is bigger, y is bigger, or they are the same.
MSDN
Compares two objects and returns a value indicating whether one is
less than, equal to, or greater than the other.
With this code, suppose X was 1000 and Y was 15. Your result would be 985, which doesn't make sense here.
Given your code and method name, I'm going to guess what you meant is this:
public class NullsAreLast : IComparer<int?>
{
public int Compare (int? x, int? y)
{
if(y == null)
return -1;
else if(x == null)
return 1;
else{
int diff = x - y;
if (diff == 0) return 0; //same
if (diff < 0) return 1; //y was bigger
if (diff > 0) return -1; //x was bigger
}
}
}
You could even smash it into a horrible one-liner:
return (y==null?-1:(x==null?1:(x-y==0?0:(x-y<0?1:-1))));
I am wondering if what i am going to do is good or bad thing. I have that class:
public class Element : IElement
{
public float? Max { get; private set; }
public float? Min { get; private set; }
public float? Average { get; private set; }
public bool HasValue { get; private set; }
public void SetRange(float? min, float? max)
{
if (min >= max)
{
throw new WrongElementValueException("Min must be greater than max!");
}
else if (min < 0f || max < 0f)
{
throw new WrongElementValueException("Min/max must be greater than 0!");
}
else if (min > 100f || max > 100f)
{
throw new WrongElementValueException("Min/max must be lesser than 0!");
}
else
{
Min = min;
Max = max;
Average = (min + max)/2f;
HasValue = true;
}
}
}
The user will set the values using SetRange() method. But he has some constraints like Min must be bigger than Max, and neither of them should be bigger than 100 or lesser than 0.
Should I use those exceptions in this place? Or is there any better method to handle wrong user input?
I hope my question isn't to general.
This is an appropriate practice, yes.
Though I imagine consuming code would be expecting an ArgumentException rather than this exception type, but that may be a relatively minor point.
When the input is invalid, and the object has no way of meaningfully continuing otherwise, then throwing an exception is an appropriate and expected response. It's up to consuming code to use the object properly, handle errors, report back to the user, etc.
The alternative is for this object to "try to figure out what to do" which often leads to some pretty bad coding practices. For example...
Suppose you instead want to return an error message instead of throwing an exception. What if consuming code doesn't check for that error message? The object would be left in an unknown and invalid state and could quietly introduce bugs. Whereas if consuming code didn't check for the exception then the program would clearly and obviously fail and would need to be appropriately corrected. Clear and obvious failures are a lot easier to support than subtle and unnoticed ones.
Suppose you want to "show a message to the user" instead. That would requiring tightly coupling this object to a presentation layer, which defeats object oriented principles and makes the code very rigid and difficult to maintain.
This object does one thing, and only that one thing. If it's invoked in such a way that it can't do that one thing, an exception is an expected and appropriate failure condition.
else if (min < 0f || max < 0f)
throw new WrongElementValueException("Min/max must be greater than 0!");
else if (min > 100f || max > 100f)
throw new WrongElementValueException("Min/max must be lesser than 0!");
I'd note that there is already ArgumentOutOfRangeException that's defined for precisely this sort of case.
if (min >= max)
throw new WrongElementValueException("Min must be greater than max!");
This should definitely be an ArgumentException, but if WrongElementValueException inherits from ArgumentException, then that's fine.
Your general approach is sound. I'd consider going further:
HasValue = true;
Why allow for the class to ever not have a value. Consider if you add:
public Element(float min, float max)
{
SetRange(min, max);
}
Now you can never have an instance without its values set, and can get rid of HasValue entirely.
Note though that I changed this from float? to float. You might well be advised to do that throughout the class. Otherwise if you have a need for cases where Min and Max are null, (and therefore don't want to get rid of HasValue) you need to catch that case in SetRange:
public void SetRange(float? min, float? max)
{
if (min < 0f || max < 0f || min > 100f || max > 100f)
throw new ArgumentOutOfRangeException();
if (min >= max)
throw new WrongElementValueException("Min must be greater than max!");
Min = min;
Max = max;
if(min.HasValue && max.HasValue)
{
Average = (min + max)/2f;
HasValue = true;
}
else
{
Average = null;
HasValue = false;
}
}
(I'd also generally favour double and double? over float and float? unless you've a strong reason otherwise).
Incidentally, we generally use "exception handling" to talk about how code that's using this code deals with the fact that your code threw an exception, with just what the best thing to do is depending on the context of that code rather than this code.
An excption is usefull whenever a valid program-flow is not possible (e.g. connection to database lost). Proofing user-input and throwing exception if values are not valid is absolutely ok thus, whereas you may also use the allready suggested ArgumentException.
It's good practice to handle exception in program if you are throwing and catching it correctly. But here it's trivial matter ,no need to throw and object where as you can restrict it by simple console print.
Both will work same in this scenario.
Throwing an exception would much useful when there are many inner function calls and you don't know which one will cause exception at that time.
and By the way don't you think these is wrong one.
if (min >= max)
throw new WrongElementValueException("Min must be greater than max!");// your are printing min should be greater than max and you are checking the same.
I have the following block of code:
if (x > 5)
{
if (!DateTime.TryParse(y, out z))
break;
if (w.CompareTo(z) == -1)
break;
}
Where x is an integer, y is a string, z and w are DateTime variables.
The reason for the break; is that whole block resides within a loop.
Is there any way this could be simplified to make it easier to read?
You don't need multilpe if blocks to execute the code because you are only doing one of two things, executing the loop or not executing the loop (one if and one else). As shown here you can use a single boolean expression to represent whether or not you should skip that loop iteration or not.
(x > 5) && (!DateTime.TryParse(y, out z) || w.CompareTo(z) == -1)
Having said that, including a complex condition like this inside of a loop can hamper readability. Personally, I would simply extract this condition out into a method so that the loop looked something like this:
while(!done) // or whatever the while loop condition is
{
if(itemIsValid(x, y, w, out z))
{
//the rest of your loop
}
}
//it may make sense for x, y, w, and possibly z to be wrapped in an object, or that already may be the case. Consider modifying as appropriate.
//if any of the variables are instance fields they could also be omitted as parameters
//also don't add z as an out parameter if it's not used outside of this function; I included it because I wasn't sure if it was needed elsewhere
private bool itemIsValid(int x, string y, DateTime w, out DateTime z)
{
return (x > 5)
&& (!DateTime.TryParse(y, out z) || w.CompareTo(z) == -1)
}
This has several advantages. First, it is a way of self-documenting the code without even needing comments. When looking at the loop you can read it as, "while I'm not done, and if the item is valid, do all of this stuff". If you are interested in how validity is defined you look at the method, if not you skip it. You could also rename the method to something more specific, such as "isReservationSlotFree" or whatever this is actually representing.
If your validation logic is complex (this is somewhat complex) it allows you to add comments and explanation without cluttering the more complex loop.
if (x > 5)
{
if(!DateTime.TryParse(y,out z) || w.CompareTo(z) == -1)
break;
}
Since the two conditionals have the same result, they can be combined into one.
if ((x > 5) && (!DateTime.TryParse(y, out z) || w.CompareTo(z) == -1))
break;
'Simplified' does not mean easier to read.
You can make your code easier to read (and more secured in regards of various coding rules) by:
1) always using brackets for if statements and alikes
2) avoid using '!' ( '== false' is much more explicit)
3) use variable names that explicit what those variables are.
4) avoid multiple break statements. Instead, use a flag that is evaluated in the while's condition.
5) if your code is still hard to read: use comments !
More important: use descriptive variable names for w, x, y, z (hopefully these names were just for your example):
You can also use the less than or greater than operators instead of CompareTo.
if (x > 5)
{
bool isValidDate = DateTime.TryParse(y, out z);
if (!isValidDate || z > w)
{
// comment like: stop processing if the current date
// is after the reference date, or if there was a parsing error
break;
}
}
Here is one more version.
var Break = x > 5 ? ((!DateTime.TryParse(y, out z) || w.CompareTo(z) == -1) ? true : false) : false;
Short but hampers the readability.
if ( x > 5 ){
if (!DateTime.TryParse(y, out z) || w.CompareTo(z) == -1) break;
}
Handling integer overflow is a common task, but what's the best way to handle it in C#? Is there some syntactic sugar to make it simpler than with other languages? Or is this really the best way?
int x = foo();
int test = x * common;
if(test / common != x)
Console.WriteLine("oh noes!");
else
Console.WriteLine("safe!");
I haven't needed to use this often, but you can use the checked keyword:
int x = foo();
int test = checked(x * common);
Will result in a runtime exception if overflows. From MSDN:
In a checked context, if an expression produces a value that is
outside the range of the destination type, the result depends on
whether the expression is constant or non-constant. Constant
expressions cause compile time errors, while non-constant expressions
are evaluated at run time and raise exceptions.
I should also point out that there is another C# keyword, unchecked, which of course does the opposite of checked and ignores overflows. You might wonder when you'd ever use unchecked since it appears to be the default behavior. Well, there is a C# compiler option that defines how expressions outside of checked and unchecked are handled: /checked. You can set it under the advanced build settings of your project.
If you have a lot of expressions that need to be checked, the simplest thing to do would actually be to set the /checked build option. Then any expression that overflows, unless wrapped in unchecked, would result in a runtime exception.
Try the following
int x = foo();
try {
int test = checked (x * common);
Console.WriteLine("safe!");
} catch (OverflowException) {
Console.WriteLine("oh noes!");
}
The best way is as Micheal Said - use Checked keyword.
This can be done as :
int x = int.MaxValue;
try
{
checked
{
int test = x * 2;
Console.WriteLine("No Overflow!");
}
}
catch (OverflowException ex)
{
Console.WriteLine("Overflow Exception caught as: " + ex.ToString());
}
Sometimes, the simplest way is the best way. I can't think a better way to write what you wrote, but you can short it to:
int x = foo();
if ((x * common) / common != x)
Console.WriteLine("oh noes!");
else
Console.WriteLine("safe!");
Note that I didn't remove the x variable because it'd be foolish to call the foo() three times.
Old thread, but I just ran into this. I didn't want to use exceptions. What I ended up with was:
long a = (long)b * (long)c;
if(a>int.MaxValue || a<int.MinValue)
do whatever you want with the overflow
return((int)a);
So, I ran into this far after the fact, and it mostly answered my question, but for my particular case (in the event anyone else has the same requirements), I wanted anything that would overflow the positive value of a signed int to just settle at int.MaxValue:
int x = int.MaxValue - 3;
int someval = foo();
try
{
x += someval;
}
catch (OverflowException)
{
x = int.MaxValue;
}