I have two alternative code fragments, with an intention to do (approximately) the same:
Closed-ended condition, with 3 cases of inputs resulting into just 2 cases of outputs:
this.showDropdowns ? parseInt(this.uploadForm.get('location').value, 10) : null;
Open-ended conditioning, with 3 possible cases of inputs resulting into 3 recombined (table non-plain matching) cases of outputs:
try {parseInt(this.uploadForm.get('location').value, 10)} catch (ParseIntError e) {return null;}
The first case is strict, allowing only the two resulting options explicitly prepared by the programmer: Either gives null (i), or the parsed value (ii), or the parsing falls (iii) back to the null.
See the Closed/Open questions described on Wikipedia, to understand me what I mean.
The second code-fragment is not so greedy, does not swallow any possible exception, so the values are the two (three) expected by a programmer: The successfully parsed value (a), or there is still an allowed option for any unexpected result, as an explicitly caught Exception (also merging the null input/output case (b) with the parsing error exception (c), the non-null input, to be parsed, but unprocessable), but still yet allowing a fourth case of whatever completely unimaginable in the moment of the programming (d), still letting it to bubble up as an uncaught exception.
The inputs could be just two, in general: null, or an Object.
The outputs on the other hand could be more complicated:
the hardcoded null, after the IF;
the successfully parsed value;
or Exceptions:
Completely wrong Object-type for the particular parsing.
Parsable Object-type, but wrong values in it, in many ways...
So the questions:
Is the first one too naive and too greedy, swallowing too much, or oppositely the aggregation/swallowing is the recommended way?
Would the second be misusing of the mechanism of exceptions, or just the standard plain usage?
Are these known distinguished cases/options, how to resolve problems? These might be even so general, that there are some rules, philosophical how-to's or Good practices, to judge/recognize, when exactly to use the 1st, or the 2nd? So what are the rules, the recommendations? Thanks.
Related
Consider the following interface:
public interface AISPI
{
public Path getPath(Entity entity, Entity target, World world) throws NoPathException;
}
Granted that entity, target, and world are all valid input. But the algorithm used to find a path (it is Astar in this case) fails to find a path, due to eg. the position of target being surrounded by concrete walls.
Is it valid to state that the postcondition is either a Path from entity to target (start to goal) or a NoPathException (given that a path was not found)?
- Or should the precondition state that there must be a valid path from start to goal?
This is not homework, but a question for improving our semester project report. I am not looking to learn about any frameworks, this is purely a question of standards and formalities in regards to design by contract. Thanks for any clarification on the matter.
It depends on the definition of the term postcondition. In general, a precondition is a relation on input state and input values at routine entry, and a postcondition is a relation on input state, input values and output state and output values at routine exit.
Because a routine can exit either normally or exceptionally, it is possible to define a postcondition for normal termination and a postcondition for abnormal termination. Clearly both involve input values, input state and output state. The key difference is in output values. In the first case this is a value specified in the routine signature, in the second - it depends on the language. In your example it might be NoPathException, but what if there is a memory allocation error, stack overflow or other exception or signal that is not specified in the signature? It may indeed seem to be possible to have a precondition that guarantees that there is always a valid result that does not involve exceptions. But this is not the case, e.g. when there is communication to external world, concurrency, etc. Also if a precondition is too costly to compute, it does not look nice to do the same work twice - on the client side to make sure a call is applicable and on the supplier's side to do essentially the same computation to get the result.
According to the Design by Contract philosophy a postcondition is what the client can safely rely on after calling a routine. Coming back to the exceptional case, from the practical point of view it makes sense to make the abnormal postcondition strong enough so that a program can continue execution, but weak enough so that the cases that are not or cannot be specified in the signature, but are possible in practice, are allowed.
So, unless the language does really guarantee all possible exceptional cases and nothing else, the most important part is output state that should not make the associated objects unusable. And this could either be expressed in an explicit or implicit postcondition or as a class invariant.
As to the specific example with getPath, the situation when a path does not exist is normal, i.e. it may happen, is expected. Some guidelines recommend to use normal values to indicate normal termination cases. Here it would be value null. Using null may lead to other issues on the caller's side, such as NullPointerException if result is not checked for null-ness, but in some languages that guarantee absence of such exceptions (e.g., void-safety in Eiffel) this would be the preferred way to indicate absence of a path (the return type would be detachable PATH in that case).
For example, in the case of "The array index out of bound" exception, why don't we check the array length in advance:
if(array.length < countNum)
{
//logic
}
else
{
//replace using exception
}
My question is, why choose to use an exception? and when to use an exception, instead of if-else
Thanks.
It depends on acceptable practices for a given language.
In Java, the convention is to always check conditions whenever possible and not to use exceptions for flow control. But, for example, in Python not only using exception in this manner is acceptable, but it is also a preferred practice.
They are used to inform the code that calls your code an exceptional condition occurred. Exceptions are more expensive than well formed if/else logic so you use them in exceptional circumstances such as reaching a condition in your code you cannot handle locally, or to support giving the caller of your code the choice of how to handle the error condition.
Usually if you find yourself throwing and catching exceptions in your own function or method, you can probably find a more efficient way of doing it.
There are many answers to that question. As a single example, from Java, when you are using multiple threads, sometimes you need to interrupt a thread, and the thread will see this when an InterruptedException is thrown.
Other times, you will be using an API that throws certain exceptions. You won't be able to avoid it. If the API throws, for example, an IOException, then you can catch it, or let it bubble up.
Here's an example where it would actually be better to use an exception instead of a conditional.
Say you had a list of 10,000 strings. Now, you only want those items which are integers. Now, you know that a very small number of them won't be integers (in string form). So should you check to see if every string is an integer before trying to convert them? Or should you just try to convert them and throw and catch an exception if you get one that isn't an integer? The second way is more efficient, but if they were mostly non-integers then it would be more efficient to use an if-statement.
Most of the time, however, you should not use exceptions if you can replace them with a conditional.
As someone has already said, 'Exceptions' in programming languages are for exceptional cases and not to set logical flow of your program. For example, in the case of given code snippet of your question, you have to see what the enclosing method's or function's intention is. Is checking array.length < countNum part of the business logic or not. If yes, then putting a pair of if/else there is the way to go. If that condition is not part of the business logic and the enclosing method's intention is something else, then write code for that something else and throw exception instead of going the if/else way. For example you develop an application for a school and in your application you have a method GetClassTopperGrades which is responsible for the business logic part which requires to return the highest marks of the student in a certain class. the method/function definition would be something like this:
int GetClassTopperGrades(string classID)
In this case the method's intention is to return the grades, for a valid class, which will always be a positive integer, according to the business logic of the application. Now if someone calls your method and passes a garbage string or null, what should it do? If should throw an exception e.g. ArgumentException or 'ArgumentNullException' because this was an exceptional case in this particular context. The method assumed that always a valid class ID will be passed and NULL or empty string is NOT a valid class ID (a deviation from the business logic).
Apart from that, in some conditions there is no prior knowledge about the outcome of a given code and no defined way to prevent an exceptional situation. For example, querying some remote database, if the network goes down, you don't have any other option there apart from throwing an exception. Would you check network connectivity before issuing every SQL query to the remote database?
There is strong and indisputable reason why to use exceptions - no matter of language. I strongly believe that decision about if to use exceptions or not have nothing to do with particular language used.
Using exceptions is universal method to notify other part of code that something wrong happened in kind of loosely coupled way. Let imagine that if you would like to handle some exceptional condition by using if.. nad else.. you need to insert into different part of your code some arbitrary variables and other stuff which probably would easily led to have spaghetti code soon after.
Let next imagine that you are using any external library/package and it's author decided to put in his/her code other arbitrary way to handle wrong states - it would force you to adjust to its way of dealing with it - for example you would need to check if particular methods returns true or false or whatever. Using exceptions makes handling errors much more easy - you just assume that if something goes wrong - the other code will throw exception, so you just wrap the code in try block and handle possible exception on your own way.
I'm having a hard time choosing whether I should "enforce" a condition or "assert" a condition in D. (This is language-neutral, though.)
Theoretically, I know that you use assertions to find bugs, and you enforce other conditions in order to check for atypical conditions. E.g. you might say assert(count >= 0) for an argument to your method, because that indicates that there's a bug with the caller, and that you would say enforce(isNetworkConnected), because that's not a bug, it's just something that you're assuming that could very well not be true in a legitimate situation beyond your control.
Furthermore, assertions can be removed from code as an optimization, with no side effects, but enforcements cannot be removed because they must always execute their condition code. Hence if I'm implementing a lazy-filled container that fills itself on the first access to any of its methods, I say enforce(!empty()) instead of assert(!empty()), because the check for empty() must always occur, since it lazily executes code inside.
So I think I know that they're supposed to mean. But theory is easier than practice, and I'm having a hard time actually applying the concepts.
Consider the following:
I'm making a range (similar to an iterator) that iterates over two other ranges, and adds the results. (For functional programmers: I'm aware that I can use map!("a + b") instead, but I'm ignoring that for now, since it doesn't illustrate the question.) So I have code that looks like this in pseudocode:
void add(Range range1, Range range2)
{
Range result;
while (!range1.empty)
{
assert(!range2.empty); //Should this be an assertion or enforcement?
result += range1.front + range2.front;
range1.popFront();
range2.popFront();
}
}
Should that be an assertion or an enforcement? (Is it the caller's fault that the ranges don't empty at the same time? It might not have control of where the range came from -- it could've come from a user -- but then again, it still looks like a bug, doesn't it?)
Or here's another pseudocode example:
uint getFileSize(string path)
{
HANDLE hFile = CreateFile(path, ...);
assert(hFile != INVALID_HANDLE_VALUE); //Assertion or enforcement?
return GetFileSize(hFile); //and close the handle, obviously
}
...
Should this be an assertion or an enforcement? The path might come from a user -- so it might not be a bug -- but it's still a precondition of this method that the path should be valid. Do I assert or enforce?
Thanks!
I'm not sure it is entirely language-neutral. No language that I use has enforce(), and if I encountered one that did then I would want to use assert and enforce in the ways they were intended, which might be idiomatic to that language.
For instance assert in C or C++ stops the program when it fails, it doesn't throw an exception, so its usage may not be the same as what you're talking about. You don't use assert in C++ unless you think that either the caller has already made an error so grave that they can't be relied on to clean up (e.g. passing in a negative count), or else some other code elsewhere has made an error so grave that the program should be considered to be in an undefined state (e.g. your data structure appears corrupt). C++ does distinguish between runtime errors and logic errors, though, which may roughly correspond but I think are mostly about avoidable vs. unavoidable errors.
In the case of add you'd use a logic error if the author's intent is that a program which provides mismatched lists has bugs and needs fixing, or a runtime exception if it's just one of those things that might happen. For instance if your function were to handle arbitrary generators, that don't necessarily have a means of reporting their length short of destructively evaluating the whole sequence, you'd be more likely consider it an unavoidable error condition.
Calling it a logic error implies that it's the caller's responsibility to check the length before calling add, if they can't ensure it by the exercise of pure reason. So they would not be passing in a list from a user without explicitly checking the length first, and in all honesty should count themselves lucky they even got an exception rather than undefined behavior.
Calling it a runtime error expresses that it's "reasonable" (if abnormal) to pass in lists of different lengths, with the exception indicating that it happened on this occasion. Hence I think an enforcement rather than an assertion.
In the case of filesize: for the existence of a file, you should if possible treat that as a potentially recoverable failure (enforcement), not a bug (assertion). The reason is simply that there is no way for the caller to be certain that a file exists - there's always someone with more privileges who can come along and remove it, or unmount the entire fielsystem, in between a check for existence and a call to filesize. It's therefore not necessarily a logical flaw in the calling code when it doesn't exist (although the end-user might have shot themselves in the foot). Because of that fact it's likely there will be callers who can treat it as just one of those things that happens, an unavoidable error condition. Creating a file handle could also fail for out-of-memory, which is another unavoidable error on most systems, although not necessarily a recoverable one if for example over-committing is enabled.
Another example to consider is operator[] vs. at() for C++'s vector. at() throws out_of_range, a logic error, not because it's inconceivable that a caller might want to recover, or because you have to be some kind of numbskull to make the mistake of accessing an array out of range using at(), but because the error is entirely avoidable if the caller wants it to be - you can always check the size() before access if you have no other way of knowing whether your index is good or not. And so operator[] doesn't guarantee any checks at all, and in the name of efficiency an out of range access has undefined behavior.
assert should be considered a "run-time checked comment" indicating an assumption that the programmer makes at that moment. The assert is part of the function implementation. A failed assert should always be considered a bug at the point where the wrong assumption is made, so at the code location of the assert. To fix the bug, use a proper means to avoid the situation.
The proper means to avoid bad function inputs are contracts, so the example function should have a input contract that checks that range2 is at least as long as range1. The assertion inside the implementation could then still remain in place. Especially in longer more complex implementations, such an assert may inprove understandability.
An enforce is a lazy approach to throwing runtime exceptions. It is nice for quick-and-dirty code because it is better to have a check in there rather then silently ignoring the possibility of a bad condition. For production code, it should be replaced by a proper mechanism that throws a more meaningful exception.
I believe you have partly answered your question yourself. Assertions are bound to break the flow. If your assertion is wrong, you will not agree to continue with anything. If you enforce something you are making a decision to allow something to happen based on the situation. If you find that the conditions are not met, you can enforce that the entry to a particular section is denied.
Is it always a bad programming technique to leave a catch block empty when using a try-catch block?
In cases where I am expecting an exception, for example, I am reading 10 values from a file...and converting each value into a String. There is a possibility that one of the 10 values can be a null, but I don't want to stop my execution at that point and rather continue (obvious use of try catch)
A lame example of what I am trying:
String _text = textReader.ReadLine(); //Assuming this RETURNS a NULL value
try {
String _check = _text.ToString();
//Do something with _check, but it should not be NULL
}
catch (Exception)
{ //Do Nothing }
At this point, when I catch an exception:
1. I don't want to log this. Since I am expecting a buggy value.
2. I don't want to re-throw the exception up the call-stack.
3. I want to simply continue with my execution
Under these cases, is it acceptable to leave the catch empty? Or is this a complete NO-NO and there is a better way to handle this?
I presume this can be a community wiki since it also deals with programming techniques.
- Ivar
I assume that you mean
_text.ToString()
and you're concerned about the case when _text may be null?
I don't like your use of exceptions in this case. Put yourself in the mind of someone needing to maintain this code. They see:
catch (Exception) { }
Can they really deduce that all this is doing is catching the Null case? They have to consider what other Exceptions might be thrown. At the very least this raises uncertainty in the maintainer's mind.
Why could you not code:
if ( _text != null ) {
String _check = _nullValue.ToString();
}
This says exactly what you mean.
But taking this further, what does getting a value of NULL mean? You're reading a file that may have 10 values in it. I'm guessing that maybe blank line gives a null for you?
What do intend if you get:
1
2
<blank line>
4
...
10
So that's 9 good values and a blank line. What will you do if instead you get 10 good values and a blank line? 11 good values? 11 good values and a blank line?
My point is that silently ignoring oddities in user input is often a bad idea. It's quite likely that some of the cases above are actually typos. By warning in some of these cases you may be very helpful to the user. This implies that probably most odditities in input need at least some kind of count, if not an actual immediate error log.
You might, for example, emit a message at the end
Your file contained 13 lines, two lines were blank. We processed 10 valid values and ignored one.
At the very leasyt for debugging purposes you might have trace statements in the error paths.
Summary: completely ignoring Exceptions is rarely the right thing to do.
If it's expected it's not really exceptional. Is this a good use of exceptions? It may be more appropriate to test for a null value before trying to do stuff.
if(_text != null)
// do something
The best argument I liked was that the code will become highly un-maintainable. And my aim was to make my code as easy to understand as possible.
With the suggestions above, I have an army of ternary operators in place (my personal favorite over big if-else blocks).
And the code definitely looks better! and I think unless the try-catch is well documented, I don't myself see a good reason for having empty catch statements anymore.
Thanks Guys!!
-Ivar
I have been doing some work with python-couchdb and desktopcouch. In one of the patches I submitted I wrapped the db.update function from couchdb. For anyone that is not familiar with python-couchdb the function is the following:
def update(self, documents, **options):
"""Perform a bulk update or insertion of the given documents using a
single HTTP request.
>>> server = Server('http://localhost:5984/')
>>> db = server.create('python-tests')
>>> for doc in db.update([
... Document(type='Person', name='John Doe'),
... Document(type='Person', name='Mary Jane'),
... Document(type='City', name='Gotham City')
... ]):
... print repr(doc) #doctest: +ELLIPSIS
(True, '...', '...')
(True, '...', '...')
(True, '...', '...')
>>> del server['python-tests']
The return value of this method is a list containing a tuple for every
element in the `documents` sequence. Each tuple is of the form
``(success, docid, rev_or_exc)``, where ``success`` is a boolean
indicating whether the update succeeded, ``docid`` is the ID of the
document, and ``rev_or_exc`` is either the new document revision, or
an exception instance (e.g. `ResourceConflict`) if the update failed.
If an object in the documents list is not a dictionary, this method
looks for an ``items()`` method that can be used to convert the object
to a dictionary. Effectively this means you can also use this method
with `schema.Document` objects.
:param documents: a sequence of dictionaries or `Document` objects, or
objects providing a ``items()`` method that can be
used to convert them to a dictionary
:return: an iterable over the resulting documents
:rtype: ``list``
:since: version 0.2
"""
As you can see, this function does not raise the exceptions that have been raised by the couchdb server but it rather returns them in a tuple with the id of the document that we wanted to update.
One of the reviewers went to #python on irc to ask about the matter. In #python they recommended to use sentinel values rather than exceptions. As you can imaging just an approach is not practical since there are lots of possible exceptions that can be received. My questions is, what are the cons of using Exceptions over sentinel values besides that using exceptions is uglier?
I think it is ok to return the exceptions in this case, because some parts of the update function may succeed and some may fail. When you raise the exception, the API user has no control over what succeeded already.
Raising an Exception is a notification that something that was expected to work did not work. It breaks the program flow, and should only be done if whatever is going on now is flawed in a way that the program doesn't know how to handle.
But sometimes you want to raise a little error flag without breaking program flow. You can do this by returning special values, and these values can very well be exceptions.
Python does this internally in one case. When you compare two values like foo < bar, the actual call is foo.__lt__(bar). If this method raises an exception, program flow will be broken, as expected. But if it returns NotImplemented, Python will then try bar.__ge__(foo) instead. So in this case returning the exception rather than raising it is used to flag that it didn't work, but in an expected way.
It's really the difference between an expected error and an unexpected one, IMO.
exceptions intended to be raised. It helps with debugging, handling causes of the errors and it's clear and well-established practise of other developers.
I think looking at the interface of the programme, it's not clear what am I supposed to do with returned exception. raise it? from outside of the chain that actually caused it? it seems a bit convoluted.
I'd suggest, returning docid, new_rev_doc tuple on success and propagating/raising exception as it is. Your approach duplicates success and type of 3rd returned value too.
Exceptions cause the normal program flow to break; then exceptions go up the call stack until they're intercept, or they may reach the top if they aren't. Hence they're employed to mark a really special condition that should be handled by the caller. Raising an exception is useful since the program won't continue if a necessary condition has not been met.
In languages that don't support exceptions (like C) you're often forced to check return values of functions to verify everything went on correctly; otherwise the program may misbehave.
By the way the update() is a bit different:
it takes multiple arguments; some may fail, some may succeed, hence it needs a way to communicate results for each arg.
a previous failure has no relation with operations coming next, e.g. it is not a permanent error
In that situation raising an exception would NOT be usueful in an API. On the other hand, if the connection to the db drops while executing the query, then an exception is the way to go (since it's a permament error and would impact all operations coming next).
By the way if your business logic requires all operations to complete successfully and you don't know what to do when an update fails (i.e. your design says it should never happen), feel free to raise an exception in your own code.