Java Forum / General / January 2006
Variable naming problem
Roedy Green - 22 Jan 2006 07:52 GMT It is very common for a method to return a boolean that indicates success/fail of some test or operation.
E.g. testing if a date is valid, if a file was successfully saved etc.
So two questions:
Which convention do you use? true= good or true=problem?
Why? How do you make that clear to others?
If you have to represent the state in side the method with a boolean variable, what do you call it?
state, success, status, ok, wasSuccessful..?
How is your true/false convention make obvious by your choice of name?
When you say "return success" how do you avoid confusing people? Are you returning good or the state?
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Luke Meyers - 22 Jan 2006 09:04 GMT > It is very common for a method to return a boolean that indicates > success/fail of some test or operation. [quoted text clipped - 4 lines] > > Which convention do you use? true= good or true=problem? true == good, allowing idioms like:
if (openFile(filename)) processFile(); else reportError();
> Why? How do you make that clear to others? The opposite would be misleading. I would make sure to name my methods appropriately to avoid other sources of possible ambiguity. And, of course, provide appropriate documentation in a @return javadoc tag.
> If you have to represent the state in side the method with a boolean > variable, what do you call it? > > state, success, status, ok, wasSuccessful..? If the only use of the boolean variable is to return it, but for some reason it must be assigned to a named variable (rather than simply returned immediately), I often just call it something like "retval." It's concise and obvious. "status" is also reasonable in many cases.
> When you say "return success" how do you avoid confusing people? Are > you returning good or the state? That's a reasonable argument against using identifiers such as "success" for this purpose.
I rarely run into any real problems related to the issues you're asking about, though. Methods should not be so convoluted that a reader has trouble understanding the meaning of the return value just because it's called "success" or whatever. Focus on writing comprehensible code and keeping method size under control, and problems like this tend to solve themselves.
Luke
opalpa@gmail.com opalinski from opalpaweb - 22 Jan 2006 13:53 GMT I choose words for the situation and do not use retval. If the test was to see whether a file is open then the boolean name would be "open". If the test was to see whether something was small then the boolean name would be "small". If the test was to see that we are at end of line the boolean would be "eol".
A general rule is look at Brian Kernighan's code and make your code like his.
Opalinski opalpa@gmail.com http://www.geocities.com/opalpaweb/
ricky.clarkson@gmail.com - 22 Jan 2006 15:28 GMT I'd go one step further than Opalinski: isOpen, isSmall, atEol
Hal Rosser - 23 Jan 2006 03:18 GMT > I'd go one step further than Opalinski: isOpen, isSmall, atEol Bingo - that's the most descriptive naming convention. isOpen, fileExists, isAppended, isPrime, isFirst, etc etc
NullBock - 22 Jan 2006 12:56 GMT > It is very common for a method to return a boolean that indicates > success/fail of some test or operation.
> How do you make that clear to others? It shouldn't be too hard, if such methods are used properly. It is certainly valid to have a method return true/false to test some condition; such methods are best named to make the result as clear as possible. In your example, a method testing a date might well be named
isDateValid(Date) : boolean
Then it's clear that "true" means that the date is valid, "false" otherwise.
Operations that return a success/failure code should be avoided, though. Not only do such methods make the code more obscure, but they rely on all client code to do the right thing. Exceptions are a much better possibility; they are unabmbiguous, and don't require superfluous return-test code.
This isn't just my opinion either--Bloch covers this in his "Effective Java" book.
Walter Gildersleeve Freiburg, Germany
______________________________________________________ http://linkfrog.net URL Shortening Free and easy, small and green.
Stefan Schulz - 22 Jan 2006 20:29 GMT > Operations that return a success/failure code should be avoided, > though. Not only do such methods make the code more obscure, but they > rely on all client code to do the right thing. Exceptions are a much > better possibility; they are unabmbiguous, and don't require > superfluous return-test code. Absolutely agreed. For failures, exceptions are the proper language facility to use, return values are for "normal" results.
Luke Meyers - 22 Jan 2006 22:10 GMT > It shouldn't be too hard, if such methods are used properly. It is > certainly valid to have a method return true/false to test some [quoted text clipped - 5 lines] > Then it's clear that "true" means that the date is valid, "false" > otherwise. Otherwise known as a "predicate." No argument from anyone on this idiom, I would hope -- it's simple and intuitive.
> Operations that return a success/failure code should be avoided, > though. Not only do such methods make the code more obscure, but they > rely on all client code to do the right thing. Exceptions are a much > better possibility; they are unabmbiguous, and don't require > superfluous return-test code. I would hesitate to agree to a universal policy of always using exceptions to represent any result which is semantically negative. When you use exceptions, you pay for exceptions, namely:
(1) Runtime overhead. Throwing an exception, unwinding the stack, etc., is much more expensive than simply returning a boolean value. In an efficiency-critical section of code, it makes sense to minimize exception usage when a good alternative is available.
(2) Syntactic overhead. The proliferation of try/catch/finally blocks associated with heavy use of exceptions can easily send what should be a simple method body into deeply-nested curly brace hell. When it's the difference between fitting your method all onto one screen or not, what's the best choice from a maintainability perspective?
Now, exceptions have their place. They're a useful mechanism and should see plenty of use in any well-designed programs. But there are plenty of times where returning false is just as clear, faster, and more concise.
> This isn't just my opinion either--Bloch covers this in his "Effective > Java" book. I'll have to check that section in my copy at work tomorrow. I recall his section on using exceptions to represent exceptional conditions, but my recollection is mainly of his admonishment against *overuse* of exceptions (for normal control flow, etc.).
I think the useful discussion here would be, how do we distinguish failures in general from exceptional conditions? Are all failures exceptional? I think it would be going out on an uncomfortable limb to assert such. One might reasonably characterize exceptions as things which are not anticipated to occur in a successful execution path, but which we must be prepared to handle, just in case. Other sorts of failures are bound to be part of any sufficiently complex program, and it's not reasonable to think we'll often encounter an execution path completely free of failures.
Some examples of the kind of non-exceptional error I'm talking about: * A timeout which simply results in a retry. Maybe if we exhaust all our retries, *then* throw. * Validation of keyboard input. Users are bound to make typos, so validating and reprompting is just normal business logic. * A readLine() function which returns false when there is no more input. That's not an exception, it's a sentinel condition. Do you really want to use a try/catch/finally block for that?
I suppose that's a decent set of examples. Is my point well taken?
Luke
Stefan Schulz - 22 Jan 2006 22:28 GMT > I would hesitate to agree to a universal policy of always using > exceptions to represent any result which is semantically negative. [quoted text clipped - 10 lines] > the difference between fitting your method all onto one screen or not, > what's the best choice from a maintainability perspective? Both are correct and valid. However, the proposal was to use a false return value to represent some serious failure, an exceptional situation (or at least, this is how i understood the OP).
As i understood it, we are talking about "boolean doSomething()" returning false if something could not be done, instead of isEmpty(). That is, making a predicate out of an otherwise void function, by returning false on failure. Clearly, booleans do have their place, if a boolean condition is being checked (isEmpty(), for example)
Luke Meyers - 22 Jan 2006 23:54 GMT > Both are correct and valid. However, the proposal was to use a false > return value to represent some serious failure, an exceptional > situation (or at least, this is how i understood the OP). The OP made no reference to the seriousness of the failure, just that it is a failure of some kind. My whole post was about the difference between kinds of failures.
> As i understood it, we are talking about "boolean doSomething()" > returning false if something could not be done, instead of isEmpty(). Right. I dismiss predicates as valid but trivial and not an important part of this discussion.
> That is, making a predicate out of an otherwise void function, by > returning false on failure. I would hesitate to refer to anything with side-effects as a predicate. The return value, representing the success or failure of the operation, is clearly subordinate to the operation itself.
> Clearly, booleans do have their place, if a > boolean condition is being checked (isEmpty(), for example) Again, that's just a predicate. You have not in any way addressed my point that there are failures which are not exceptional. Please feel free to use the examples I provided (e.g. readLine()) as discussion points.
Luke
Stefan Schulz - 23 Jan 2006 00:25 GMT > > Both are correct and valid. However, the proposal was to use a false > > return value to represent some serious failure, an exceptional [quoted text clipped - 3 lines] > it is a failure of some kind. My whole post was about the difference > between kinds of failures. With all due respect, no. The part of your post i referenced was about "Exceptions are too expensive, lets get back to special return values". You may have a point that there are cases where a situation is not entirely common, but not yet as rare or unexpected as to justify an exception (End of Stream conditions, for example), but for the most part, you mentioned code beauty and runtime overhead as arguments against using exceptions.
> > As i understood it, we are talking about "boolean doSomething()" > > returning false if something could not be done, instead of isEmpty(). > > Right. I dismiss predicates as valid but trivial and not an important > part of this discussion. So, what are we talking about, then?
> > That is, making a predicate out of an otherwise void function, by > > returning false on failure. > > I would hesitate to refer to anything with side-effects as a predicate. > The return value, representing the success or failure of the > operation, is clearly subordinate to the operation itself. Well, we are not in functional programming land, here. Anything, even the most innocent isXYZ call, you can call may have side effects (for example, triggering some internal housekeeping of the class). Therefore, there are either no predicates at all, or we may safely call these functions predicates.
> > Clearly, booleans do have their place, if a > > boolean condition is being checked (isEmpty(), for example) > > Again, that's just a predicate. It needn't be.
> You have not in any way addressed my > point that there are failures which are not exceptional. Please feel > free to use the examples I provided (e.g. readLine()) as discussion > points. readLine does not fail on EOF, since EOF is not an exceptional circumstance, but will invariably happen. It can, however, become exceptional (for example, if it occurs inside some "record"). In this case, you should through an EOFException (as DataInput, for example, does mandate).
Similarly, keep in mind that "untrusted user input does not validate" is not an exceptional condition, nor a failure. It is a normal, expected occurance, and therefore should be treated as such.
Luke Meyers - 23 Jan 2006 01:16 GMT > > The OP made no reference to the seriousness of the failure, just that > > it is a failure of some kind. My whole post was about the difference > > between kinds of failures. > > With all due respect, no. The part of your post i referenced was about > "Exceptions are too expensive, lets get back to special return values". Fair enough; I mentioned that as well. Though I didn't generalize so recklessly as you imply. ;)
What's "special" about true and false? I'd say that returning null is much more of a "special" return value (sentinel value), and I see plenty of that in the Java code I encounter.
> You may have a point that there are cases where a situation is not > entirely common, but not yet as rare or unexpected as to justify an > exception (End of Stream conditions, for example), but for the most > part, you mentioned code beauty and runtime overhead as arguments > against using exceptions. Against using them universally for all failures, yes. I also said that there are plenty of times where exceptions are perfectly appropriate. My point is, an informed coder should have a good understanding of the tradeoffs involved, and weigh them when deciding how to represent failure conditions.
> > > As i understood it, we are talking about "boolean doSomething()" > > > returning false if something could not be done, instead of isEmpty(). [quoted text clipped - 3 lines] > > So, what are we talking about, then? Methods which perform an operation as part of a class's logical behavior, and which require some mechanism to report a failure thereof.
> Well, we are not in functional programming land, here. Anything, even > the most innocent isXYZ call, you can call may have side effects (for > example, triggering some internal housekeeping of the class). > Therefore, there are either no predicates at all, or we may safely call > these functions predicates. We're in good-design space, here, not language-lawyer space. Obviously, since Java has no "const," there's nothing preventing a method like isValid() from modifying all the state it wants. However, that would in most cases be a terribly misleading design, and we should expect better of our fellow programmers. Internal housekeeping is distinct, because it does not affect the visible state of the object. For example, if isValid() is expensive, I might compute it once and cache the result for the next call, modifying some internal state to track it. But it's still logically a predicate.
If a method's primary responsibility is to produce a boolean value, and it has no effect on logical program state, it's a predicate. If it's kind of like that but it has maybe a couple side effects, then possibly it's a poorly-designed predicate or predicate-like thing. But none of that is what we're talking about here.
> > > Clearly, booleans do have their place, if a > > > boolean condition is being checked (isEmpty(), for example) > > > > Again, that's just a predicate. > > It needn't be. What reasonable behavior could isEmpty() have?
> readLine does not fail on EOF, since EOF is not an exceptional > circumstance, but will invariably happen. It can, however, become > exceptional (for example, if it occurs inside some "record"). In this > case, you should through an EOFException (as DataInput, for example, > does mandate). You seem to be referring to some particular readLine method; I wasn't. For the sake of discussion, let's use the following alternatives:
/** * Reads a line into the internal buffer. * @return true if a line was successfully read, false otherwise */ bool readLine() { // (1) // do stuff }
/** * Reads a line into the internal buffer. * @throws EOFException if a line could not be read */ void readLine() throws EOFException { (2) // do stuff }
I don't know what you mean about a "record" -- parsing the contents of the line is clearly a separate responsibility from simply grabbing data, and should not be part of what readLine() does. Anyway, the code to use (1) would look something like:
while (readLine()) { processLine(); }
The code for (2), to accomplish the same thing, is a lot more convoluted:
try { while (true) { readLine(); processLine(); } } catch (EOFException e) { // Silently swallow exception }
This is using exceptions for control flow, against Bloch's recommendations (and common sense). But I don't think it's reasonable to say that readLine() has not failed to read a line when it encounters EOF. Its responsibility is to read a line, and it was unable to do that, so this is a failure. It's an expected failure, but that's exactly the point -- it's not exceptional.
> Similarly, keep in mind that "untrusted user input does not validate" > is not an exceptional condition, nor a failure. It is a normal, > expected occurance, and therefore should be treated as such. I would say that malformed input is a form of failure. Maybe all we're doing is disagreeing about how broadly to interpret the term "failure." In which case... well, I guess it's kind of silly to keep debating the point.
Cheers, Luke
Stefan Schulz - 23 Jan 2006 10:38 GMT > What's "special" about true and false? I'd say that returning null is > much more of a "special" return value (sentinel value), and I see > plenty of that in the Java code I encounter. And pretty often, you see it where it should not be. Many cases where "returns null if something goes wrong" is defined, that method would be better defined as throwing an exception instead.
> > You may have a point that there are cases where a situation is not > > entirely common, but not yet as rare or unexpected as to justify an [quoted text clipped - 7 lines] > tradeoffs involved, and weigh them when deciding how to represent > failure conditions. Maybe we should talk about what constitutes a failure first. For me, a failure is a condition the programmer can not reasonably expect or be expected to deal with. For example, when writing to a file, it is not reasonable to require the programmer to check before each invocation of write() if the file he/she is writing to exists, is accessible, open for writing, that the harddisk does have sufficient space remaining, and so on.
However, most data streams reach their end eventually, and pretty often, this is nothing to worry about either. This is not a failure (and therefore, not where you would use an exception), for the most part. However, if you know your file contains base64-encoded data, and ends in midst of a quartet, this becomes a failure, since an assumption you made is violated.
> > > > Clearly, booleans do have their place, if a > > > > boolean condition is being checked (isEmpty(), for example) [quoted text clipped - 4 lines] > > What reasonable behavior could isEmpty() have? Maintain an access timestamp, for example? It might also release "backing store", shrink internal arrays, and so on.
> > readLine does not fail on EOF, since EOF is not an exceptional > > circumstance, but will invariably happen. It can, however, become [quoted text clipped - 4 lines] > You seem to be referring to some particular readLine method; I wasn't. > For the sake of discussion, let's use the following alternatives: I assumed you meant the "default" readLine as maintained by javas BufferedReader class.
> /** > * Reads a line into the internal buffer. [quoted text clipped - 11 lines] > // do stuff > } This highly depends on what you expect of your lines. If a "valid" line is always terminated by some sequence (say "\r\n"), neither is a good implementation (you should both return a boolean, and possibly throw the exception). However, if the last line of your input stream may just stand on its own, then the former is the right one.
> I don't know what you mean about a "record" -- parsing the contents of > the line is clearly a separate responsibility from simply grabbing [quoted text clipped - 23 lines] > that, so this is a failure. It's an expected failure, but that's > exactly the point -- it's not exceptional. We seem to talk on cross purposes. I do not advocate exceptions for control flow. That would really be using a hammer to hand out chicken soup. However, failures (as in behaviour you are not prepared and should not have to be prepared to handle) should not be signalled by a return value - it is too easily ignored or forgotten.
> > Similarly, keep in mind that "untrusted user input does not validate" > > is not an exceptional condition, nor a failure. It is a normal, [quoted text clipped - 4 lines] > In which case... well, I guess it's kind of silly to keep debating the > point. Sure seems like it.
See you Stefan
Luke Meyers - 24 Jan 2006 03:15 GMT > Maybe we should talk about what constitutes a failure first. For me, a > failure is a condition the programmer can not reasonably expect or be [quoted text clipped - 3 lines] > for writing, that the harddisk does have sufficient space remaining, > and so on. If you define failures in that way, then don't all exceptions become fatal, since by definition they cannot be handled? I think a more reasonable approach is to recognize that certain conditions cannot be handled right away in the local scope, and so someone higher up on the stack needs to sort it out. For example, if we get a FileNotFound exception, the class responsible for handling a file may have no reasonable way to ameliorate the situation, but the GUI sitting on top of it can just query the user for different input.
That's what exceptions are useful for -- indicating error conditions that, by their nature, "want" to unwind the stack and be dealt with at a higher level. By contrast, some error conditions are almost always more appropriate to handle locally. In some of these cases, a simple return value is perfectly adequate and provides the previously-noted benefits of efficiency and conciseness.
> However, most data streams reach their end eventually, and pretty > often, this is nothing to worry about either. This is not a failure > (and therefore, not where you would use an exception), for the most > part. However, if you know your file contains base64-encoded data, and > ends in midst of a quartet, this becomes a failure, since an assumption > you made is violated. It's nothing to worry about; it just requires appropriate logic to deal with it, and that logic is separate from the logic applied when the stream has not yet ended. I think it's fair to call it a failure for a simple reason: based on just the name "readLine," when I call the method I expect it to read a line. If it does not do so (e.g. EOF), it has failed to read a line. It's not a moral judgement against the poor method, just a statement that it did not perform its advertised function.
You might be interested to read a column I found very enlightening: http://www.gotw.ca/gotw/061.htm The series of articles is oriented towards C++, but this article in particular applies just as well to Java. The author applies the ACID paradigm (Atomic, Consistent, Isolated, Durable) from database transactions to error safety. In the presented notation, a lower-case 'a' indicates that the operation is all-or-nothing; if it fails, program state is unchanged. An upper-case 'A' is a stronger guarantee, and indicates that the operation is guaranteed to succeed. One could still argue that, on reaching EOF, readLine() can still "succeed" by "successfully returning false," but I think that's stretching it. Unless readLine() always, always, always reads a line successfully, it's not capital-A Atomic, which means it sometimes fails.
> > What reasonable behavior could isEmpty() have? > > Maintain an access timestamp, for example? It might also release > "backing store", shrink internal arrays, and so on. Sure, but that's still housekeeping, not changing the logical state. Should I say "overt behavior?" "Visible behavior?"
> This highly depends on what you expect of your lines. If a "valid" line > is always terminated by some sequence (say "\r\n"), neither is a good > implementation (you should both return a boolean, and possibly throw > the exception). However, if the last line of your input stream may just > stand on its own, then the former is the right one. Ah, this brings up a very good point -- what to do in the case where both serious errors (e.g. malformed data, the sort of thing which requires a recovery action and is likely to want stack unwinding) and non-problematic failures (readLine didn't read a line, indicating end of input) can occur. One could write separate catch blocks for each, but is it really good to treat them the same?
> We seem to talk on cross purposes. I do not advocate exceptions for > control flow. That would really be using a hammer to hand out chicken > soup. However, failures (as in behaviour you are not prepared and > should not have to be prepared to handle) should not be signalled by a > return value - it is too easily ignored or forgotten. I think we're on the same page -- it's worth discussing further what is an appropriate definition of "failure" (as discussed above), but there's no point chasing any further down the path of what happens when we use different definitions -- the result is obvious. :)
I'm particularly interested in what you think of the above idea of exceptions as errors that want to propagate upwards, versus local failures that can be handled by retries, terminating loops, etc.
Luke
Stefan Schulz - 24 Jan 2006 07:37 GMT > > Maybe we should talk about what constitutes a failure first. For me, a > > failure is a condition the programmer can not reasonably expect or be [quoted text clipped - 12 lines] > reasonable way to ameliorate the situation, but the GUI sitting on top > of it can just query the user for different input. Exceptions are just that - locally fatal (strange wording, but i think it captures the gist of things rather nicely). If it is out of scope of the problems you are locally able to deal with, or expect your clients to be able to deal with, throw an exception. Some other, higher-level routine might be able to deal with that failure (for example, by removing the root cause of the exception, and retrying), but as far as you are concerned, there is not much to be done.
> That's what exceptions are useful for -- indicating error conditions > that, by their nature, "want" to unwind the stack and be dealt with at > a higher level. By contrast, some error conditions are almost always > more appropriate to handle locally. In some of these cases, a simple > return value is perfectly adequate and provides the previously-noted > benefits of efficiency and conciseness. Agreed. These conditions are usually not all that exceptional, too - instead they are conditions you expect to occur on the object, given enough time. Once more end of file is an appropriate example - it is common as dirt, and the client needs to be aware of it.
> You might be interested to read a column I found very enlightening: > http://www.gotw.ca/gotw/061.htm [quoted text clipped - 9 lines] > Unless readLine() always, always, always reads a line successfully, > it's not capital-A Atomic, which means it sometimes fails. Interesting. Maybe we all could benefit from somewhat sharper tools to distinguish one kind of occasion from the others - since with just "common sense", we are bound to trip up in semantics again.
> > > What reasonable behavior could isEmpty() have? > > [quoted text clipped - 3 lines] > Sure, but that's still housekeeping, not changing the logical state. > Should I say "overt behavior?" "Visible behavior?" All are visible one way or another. The access timestamp might be checkable through the objects interface itself, or appear in a logfile. The others might involve everything simply releasing memory to database transactions. Overt behaviour, however, is a good way to express it.
> > This highly depends on what you expect of your lines. If a "valid" line > > is always terminated by some sequence (say "\r\n"), neither is a good [quoted text clipped - 8 lines] > of input) can occur. One could write separate catch blocks for each, > but is it really good to treat them the same? In such a case, i would not advocate using an exception at all for end of input, since it is not considered exceptional (but rather non-problematic). Rather like javas standard library, you should throw an exception once you reach a unexpected / unmanageable condition, and otherwise use the sentinel. There, i said it! ;) They do have a place, but i usually strongly urge against using them, since i see them abused so frequently.
> > We seem to talk on cross purposes. I do not advocate exceptions for > > control flow. That would really be using a hammer to hand out chicken [quoted text clipped - 10 lines] > exceptions as errors that want to propagate upwards, versus local > failures that can be handled by retries, terminating loops, etc. Generally, i agree to most of your points by now. Maybe i am just a bit more trigger happy with exceptions, assuming "dumber" clients to the methods then you do. For me, anything outside the generally expected and assumed conditions is worth an exception. That is to say, if you are not reasonably sure your client will be able to handle the condition successfuly by a few stereotypal short control statements (often "if (rv == specialValue) {break;} ..."), throw that exception. If you have one of these rare few clients who are more context aware then others, it still can catch the exception. You just delegate error checking the a method which feels prepared for it, rather then forcing the caller to become more complex.
At the most basic level, all exceptions provide a very high-level means of flow control. They do just that - a non-local jump, unwinding any number of stack frames at once. This is a powerful feature, and can greatly increase code clarity since you are forced to declare what exactly can go wrong above and beyond the obvious.
On a related note, exceptions offer to provide more context intromation then sentinel values, since they are full-fledged object, and can offer more information then a simple "null" ever could. For example, theoretically, a parsing exception could point out the bad token, an XML validation exception could point to the malformed node, and so on. More then you would get by just getting a "false" return value from a validateXML() method
Luke Meyers - 25 Jan 2006 07:24 GMT > > That's what exceptions are useful for -- indicating error conditions > > that, by their nature, "want" to unwind the stack and be dealt with at [quoted text clipped - 7 lines] > enough time. Once more end of file is an appropriate example - it is > common as dirt, and the client needs to be aware of it. Surely. Those are the cases I consider reasonable candidates for indicating failure in the return type, because it's a common, easily-managed failure, and any client code that cares about it would almost inevitably use the return value as part of its control flow, e.g. checking the sentinel value to know when to break a loop.
I'm trying to think of other failures (EOF is great, but it's just one damn example ;)) that fit this criterion. I suppose there is a class of failures so insignificant that they can often be ignored. Displaying transitory, non-essential, "courtesy" output (like a brief "Please wait..." dialog) might fail, but we also might not really care. Or we might care a little, but be unable to handle the problem locally and unwilling to unwind the stack and interrupt more important logic over a trivial failure. I wonder how large is the class of failures of which we could say something similar?
> > You might be interested to read a column I found very enlightening: > > http://www.gotw.ca/gotw/061.htm [quoted text clipped - 3 lines] > distinguish one kind of occasion from the others - since with just > "common sense", we are bound to trip up in semantics again. Indeed. Since I read that article, I've been wondering whether those semantics, or a useful subset, could be enforced by the compiler or a static analysis tool. The utility of such a facility for mission-critical software would be enormous.
> In such a case, i would not advocate using an exception at all for end > of input, since it is not considered exceptional (but rather [quoted text clipped - 3 lines] > but i usually strongly urge against using them, since i see them abused > so frequently. Agreed. I've been arguing for their right to exist, not to proliferate. My first preference is of course to minimize the number of exceptional paths to begin with. After that, it's just a matter of minimizing various cost functions (runtime efficiency, readability, chance of mishandling, etc.).
> Generally, i agree to most of your points by now. Maybe i am just a bit > more trigger happy with exceptions, assuming "dumber" clients to the > methods then you do. Well, I'm certainly an advocate of defensive programming, more or less regardless of who the client is (unless it's myself, of course -- we all have a different standard for "me-only" hacks).
> For me, anything outside the generally expected > and assumed conditions is worth an exception. Another formulation of this is, any event which causes any of an operation's postconditions to fail is a failure (or exception, or what-have-you). Then one encounters the question of how much compounding to put into postconditions ("A connection is made to the server and returned" versus "A connection is made to the server and returned, OR no connection is made and null is returned."). It's a matter of taste and design judgement, more than anything.
> That is to say, if you > are not reasonably sure your client will be able to handle the > condition successfuly by a few stereotypal short control statements > (often "if (rv == specialValue) {break;} ..."), throw that exception. Agreed. I would not want to return critical information if that allowed it to be ignored.
> At the most basic level, all exceptions provide a very high-level means > of flow control. They do just that - a non-local jump, unwinding any > number of stack frames at once. This is a powerful feature, and can > greatly increase code clarity since you are forced to declare what > exactly can go wrong above and beyond the obvious. I'm not so sure about it increasing code clarity. The possibility of exceptions, particularly unchecked exceptions (RuntimeExceptions), creates a combinatorial explosion of new code paths. This complicates testability for correctness and coverage, makes it more difficult to maintain strict program integrity in the face of convoluted error scenarios, and provides a more difficult-to-trace control flow. But it's a damn good thing we have them!
I've been in C++ land lately, and since C++ does not have throws-clauses that work like in Java, I've learned some good lessons about how to be strict/paranoid w.r.t. error-safety. Java's not off the hook, of course -- remember, RuntimeExceptions (and Throwables, and Errors, IIRC) are not necessarily checked.
> On a related note, exceptions offer to provide more context intromation > then sentinel values, since they are full-fledged object, and can offer [quoted text clipped - 3 lines] > More then you would get by just getting a "false" return value from a > validateXML() method You can also return an object. Enumeration values are excellent candidates, too, and they can be as complex as you like.
Luke
Stefan Schulz - 25 Jan 2006 08:18 GMT > > At the most basic level, all exceptions provide a very high-level means > > of flow control. They do just that - a non-local jump, unwinding any > > number of stack frames at once. This is a powerful feature, and can > > greatly increase code clarity since you are forced to declare what > > exactly can go wrong above and beyond the obvious. [...]
> I've been in C++ land lately, and since C++ does not have > throws-clauses that work like in Java, I've learned some good lessons > about how to be strict/paranoid w.r.t. error-safety. Java's not off > the hook, of course -- remember, RuntimeExceptions (and Throwables, and > Errors, IIRC) are not necessarily checked. This becomes a problem of being a disciplined programmer.
Errors, by definition, are conditions that arise due to some operational constraint of the JVM or external environment, which you are never expected to "handle gracefully". Usually, the best you can do in the face of an error is bring the program down gently, instead of letting it crash and burn. Likewise, RuntimeExceptions indicate errors of the programmer. Of course, java violates that honorable principle itself (NumberFormatException, anyone? I don't know how many times i have had to write something along the line catch (NumberFormatException nfe) { /* not a number, treat as string */ } when dealing with user input). However, generally, both Errors and RuntimeExceptions do not really concern themself with the behaviour of the object itself, but either with circumstances of use (Errors), or misuse of their capabilities (RuntimeException).
> > On a related note, exceptions offer to provide more context intromation > > then sentinel values, since they are full-fledged object, and can offer [quoted text clipped - 6 lines] > You can also return an object. Enumeration values are excellent > candidates, too, and they can be as complex as you like. Sure, you can. However, this is rather cumbersome if you want to return an Object Reference rather then a boolean - you would in effect have to write a DTO for each return value, and one (or more) "Error Transfer Object", both of which inherit from some common ancestor. Both would have to be distinct types, since one offers a getResult() method, while the other would offer methods related to the kind of failure encountered. You'd have to check their type (either via some type attribute, or via RTTI), cast them to their actual type, and so on. I'll stick with exceptions. :)
Chris Smith - 25 Jan 2006 10:10 GMT > Likewise, RuntimeExceptions indicate errors > of the programmer. Of course, java violates that honorable principle > itself (NumberFormatException, anyone? I don't know how many times i > have had to write something along the line catch (NumberFormatException > nfe) { /* not a number, treat as string */ } when dealing with user > input). See java.text.NumberFormat. The reason Integer.parseInt and friends throw a RuntimeException is that they are intended to be used with private data that is maintained programmatically by the application. If you interact with the user, they are deficient in many, many ways. For example, they lack internationalization (for example, the decimal separator is always '.' rather than ','). NumberFormat has a parse that does, indeed, throw a checked exception.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Stefan Schulz - 25 Jan 2006 20:51 GMT > > Likewise, RuntimeExceptions indicate errors > > of the programmer. Of course, java violates that honorable principle [quoted text clipped - 10 lines] > separator is always '.' rather than ','). NumberFormat has a parse that > does, indeed, throw a checked exception. Of course. I referenced them because originally, they where the only build-in way to convert strings to integers - NumberFormat appeared only much much later in the SDKs evolution.
NullBock - 23 Jan 2006 12:41 GMT > I would hesitate to agree to a universal policy of always using > exceptions to represent any result which is semantically negative. So would I. "To be avoided" doesn't imply universal application.
> I'll have to check that section in my copy at work tomorrow. Unfortunately, someone seems to have taken my copy of Bloch, so I wasn't able to confirm it. Kalev does discuss just this in his "ANSI/ISO C++" book, for what it's worth.
My point was to stress the dangers of depending on return-code error checking, or having to constantly check error flags. Certainly, this is appropriate in "semantically negative," especially time-critical, operations, but that wasn't what the OP was talking about. One of his examples was seeing whether a file saved correctly. I would find any file-save routine that relied on success/failure return codes instead of exceptions to be highly suspect.
Walter Gildersleeve Freiburg, Germany
______________________________________________________ http://linkfrog.net URL Shortening Free and easy, small and green.
Chris Smith - 25 Jan 2006 10:02 GMT > I think the useful discussion here would be, how do we distinguish > failures in general from exceptional conditions? Are all failures > exceptional? Perhaps that would be a useful discussion to have. The first result would be to note that, by and large, a method whose return value is intended entirely to indicate possible failure is a surprising and generally poor idea. If it's necessary to avoid handling an exception, then it would be better to provide an API pair:
boolean canDoX(); void doX() throws CantDoXException;
(where, if it's so desirable, CantDoXException extends RuntimeException)
In that case, it IS exceptional to call doX when it's going to fail, because if you thought it might fail you ought to have called canDoX first.
> One might reasonably characterize exceptions as things > which are not anticipated to occur in a successful execution path, > but which we must be prepared to handle, just in case. I'm a little lost. The above seems to be part of the definition of all failures: not the success path, and yet may need to be handled.
> Some examples of the kind of non-exceptional error I'm talking about: I'll consider each in turn, then.
> * A timeout which simply results in a retry. Maybe if we exhaust all > our retries, *then* throw. This one I find to be extremely shaky. After all, there will almost certainly exist some level of abstraction from which it's undefined whether or not you intend to retry the operation. Finding out would be introducing knowledge dependency in the wrong direction, which leads to fragile software.
> * Validation of keyboard input. Users are bound to make typos, so > validating and reprompting is just normal business logic. Yep, definitely no exceptions needed there... though I could see the case for it. I wouldn't do it myself.
> * A readLine() function which returns false when there is no more > input. That's not an exception, it's a sentinel condition. Do you > really want to use a try/catch/finally block for that? This shouldn't even be at issue. Hitting the end of the stream in readLine() is not a failure at all; it's just the end. Of course you don't throw an exception.
Contrast with DataInputStream, though, which is generally used to read known-length atoms and sequences of data. Since you're expected to know when the data stream is done, it throws an exception if you try to read something and hit end of stream.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Roedy Green - 25 Jan 2006 13:39 GMT > boolean canDoX(); > void doX() throws CantDoXException; Exceptions should be exceptional. They obviously take much more time to process than a boolean flag on "failure".
Imagine an apple sorting machine that decides if given apple is good enough.
It makes sense for isAcceptable to return a boolean rather than throw an exception every time an apple destined for apple sauce floats by.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Tom Leylan - 22 Jan 2006 15:36 GMT "Roedy Green" <my_email_is_posted_on_my_website@munged.invalid> wrote...
> Which convention do you use? true= good or true=problem? > Why? How do you make that clear to others? I believe positive states are preferred; things like IsValid(), IsOpen() but that it can be reporting a problem situation as in IsMissing() or IsPastDue().
> If you have to represent the state in side the method with a boolean > variable, what do you call it? > > state, success, status, ok, wasSuccessful..? This is an interesting question. I adopted a simple solution decades ago and have used it in a variety of languages. I always name the return value, Result. It doesn't matter what it represents or it's datatype the last line of the function is always Return Result.
> How is your true/false convention make obvious by your choice of name? > > When you say "return success" how do you avoid confusing people? Are > you returning good or the state? You're returning the result of the function so if the function is named IsClosed() then Result is the answer to the question; is it closed? But I think you mean in an operation like Save() in which case I would return "what was the outcome of saving". The O/S may return various numeric values to indicate success or failure. If I pass these along they can good or bad so "success" or "failure" would be an assumption we can't make.
Tom
Andrew McDonagh - 22 Jan 2006 15:47 GMT > It is very common for a method to return a boolean that indicates > success/fail of some test or operation. [quoted text clipped - 6 lines] > > Why? How do you make that clear to others? i use....
if (hasMoreElements()).... if (noMoreElements()....
if (isValidBlar()).... if (notValidBlar())...
i don't ever...
if (!isValidBlar())... if (isValidBlar = false)....
...because they don't read correctly....
> If you have to represent the state in side the method with a boolean > variable, what do you call it? > > state, success, status, ok, wasSuccessful..? I can't remember doing so.... I tend to move those kind of logic into their own private methods, then use guard clause style checking in the calling method.
> How is your true/false convention make obvious by your choice of name? > > When you say "return success" how do you avoid confusing people? Are > you returning good or the state? Delphi actually has a reserved keyword 'result' for especially this purpose...
bugbear - 23 Jan 2006 15:46 GMT > if (hasMoreElements()).... > if (noMoreElements().... [quoted text clipped - 8 lines] > > ...because they don't read correctly.... Hmm. I completely disagree on your
> if (!isValidBlar())... case.
I always use "positive" names, so I would NEVER use your
if (notValidBlar())...
I would write
if(!validBlah()) ...
This avoids the possibility of ever having the awful double negative
if(!noMoreElements()) ...
Which is bad for the brain IMHO.
BugBear
Andrew McDonagh - 23 Jan 2006 19:05 GMT >> if (hasMoreElements()).... >> if (noMoreElements().... [quoted text clipped - 12 lines] > > if (!isValidBlar())... > case. Thats ok... :)
> I always use "positive" names, > so I would NEVER use your [quoted text clipped - 9 lines] > > if(!noMoreElements()) ... I wouldn't do that though...there'd be two methods and I use the positive one where needed.
if (hasMoreElements())....
> Which is bad for the brain IMHO. agreed..I wouldn't either...
> BugBear bugbear - 24 Jan 2006 10:32 GMT >> This avoids the possibility of ever having >> the awful double negative [quoted text clipped - 3 lines] > I wouldn't do that though...there'd be two methods and I use the > positive one where needed. Boy, you must like typing.
Given a "hasMoreElements()" you'd actually create
boolean hasNoMoreElements() { return !"hasMoreElements(); }
rather than use
if(!hasMoreElements()) { }
Presumably (by extension) if you have a local boolean:
boolean hasMore;
you would also have boolean hasNoMore;
and carefully assign to both of them, just in case you need the inverted sense.
Or would that be silly?
BugBear
Stefan Ram - 22 Jan 2006 15:48 GMT >It is very common for a method to return a boolean that >indicates success/fail of some test or operation. I call that a "predicate" and its invocation an "assertion".
>Which convention do you use? true= good or true=problem? None of the above. I use "true = 'what the name says'".
"Good and bad, I define these terms Quite clear, no doubt, somehow." (Bob Dylan)
>Why? It appears natural.
> How do you make that clear to others? By the name and documentation of the predicate.
>If you have to represent the state in side the method with a boolean >variable, what do you call it? >state, success, status, ok, wasSuccessful..? Here, I'd use "success".
>How is your true/false convention make obvious by your choice of name? "success = true" seems cleasr to me.
>When you say "return success" how do you avoid confusing people? Are >you returning good or the state? In C, the state would be:
return success;
While, in C, "good" often would look like:
return SUCCESS;
In Java, the meaning can be given by:
/** (...) @return ... */
Luc The Perverse - 22 Jan 2006 22:13 GMT > It is very common for a method to return a boolean that indicates > success/fail of some test or operation. [quoted text clipped - 16 lines] > When you say "return success" how do you avoid confusing people? Are > you returning good or the state? If there were some kind of difficult to avoid ambiguity, I would highly favor true meaning successful - just because of what I've seen used, and it fits well with my intuition.
The only situation even remotely similar that I can think of that deviated was a function in C returning a pointer and it would return null if it failed.
To me as a programmer true and successful are the same thing in a situation like boolean Connect(int port) or the like. Mentally I would a line like this
if(!commObject.Connect(1)) . . .
as if comm object didn't connect then . . .
Trying to resolve the ambiguity by making the function name something like ConnectSuccess or something would further complicate the matter.
But isn't the best way something of this form:
SerialConnect commObject = new SerialConnect(); try{ commObject.Connect(1); . . . } catch(SerialConnectionException e){ . . .
}
-- LTP
:) Scott Ellsworth - 23 Jan 2006 22:33 GMT > It is very common for a method to return a boolean that indicates > success/fail of some test or operation. wasFileSaved() isComputerOn(). didProgramCrash().
Read as a sentence, the true response means the affirmative.
> If you have to represent the state in side the method with a boolean > variable, what do you call it? Depends. I may call it something like ret or retVal, but for a method of any importance, it is probably called wasFileSaved.
> When you say "return success" how do you avoid confusing people? Are > you returning good or the state? If the method is called wasSaveSuccessful, then ret or wasSaveSuccessful is returned. If the method is getState, then it returns an appropriate object/primitive to hold the state. For example, getSQLException returns an SQLException.
Scott
 Signature Scott Ellsworth scott@alodar.nospam.com Java and database consulting for the life sciences
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|