File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes OO, Patterns, UML and Refactoring and the fly likes OO precondition assertion responsibilities Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of EJB 3 in Action this week in the EJB and other Java EE Technologies forum!
JavaRanch » Java Forums » Engineering » OO, Patterns, UML and Refactoring
Bookmark "OO precondition assertion responsibilities" Watch "OO precondition assertion responsibilities" New topic
Author

OO precondition assertion responsibilities

Dirk Schreckmann
Sheriff

Joined: Dec 10, 2001
Posts: 7023
Am I really being sloppy when I defer precondition assertion to a method whose API clearly states that it throws an IllegalArgumentException if the preconditions are not met?
I keep reading articles and books that would tell me to stop it.
It would seem to me that it's just plain old easier (and sometimes cleaner) to defer such responsibility to the method (or constructor) that already says it's taking care of it. Why is it so wrong for a method (or constructor) to assert (to an extent) that it's being used properly? Is the client really not supposed to make use of such a built-in assertion when the API clearly states that it's there?


[How To Ask Good Questions] [JavaRanch FAQ Wiki] [JavaRanch Radio]
Dirk Schreckmann
Sheriff

Joined: Dec 10, 2001
Posts: 7023
I guess I'm really having a problem with imagining a different MVC-like design than the one I'm using. I'm trying to simply seperate an object that does things from the GUI through which the user controls the object's creation and use. I don't like doing a bunch of math and parameter checking from the GUI. It just seems to me to be so much easier to let the object being created and used do the checks. Of course, the GUI then does have to check and handle runtime exceptions. The reality of the situation is that the exception checking and handling does appear to be a lot cleaner and simpler than a bunch of precondition checking, but I suppose that conceptually there may not be a big difference - except that conceptually the responsibility is supposed fall on the client which is supposed to be cleaner(?). So, perhaps I should just roll over and do the precondition checks... ba.
[ September 19, 2002: Message edited by: Dirk Schreckmann ]
Frank Carver
Sheriff

Joined: Jan 07, 1999
Posts: 6920
I know we are talking about cleanliness of design, here, but I tend to dislike using exceptions if they can be avoided. One of the reasons is the performance hit to generate a new exception with a stacktrace and so on.


Read about me at frankcarver.me ~ Raspberry Alpha Omega ~ Frank's Punchbarrel Blog
David Weitzman
Ranch Hand

Joined: Jul 27, 2001
Posts: 1365
If it's a GUI, the user will hardly notice the 50 milliseconds of exception handling overhead. I say let exceptions take care of it.
Dirk Schreckmann
Sheriff

Joined: Dec 10, 2001
Posts: 7023
Ach! Just when I'm trying to figure out a reasonable transition in the responsibility model I like to use, along comes Mr. Weitzman to mess with my head - or add the voice of reason.
In this situation the time it would take to create, throw and catch the exception probably isn't of much concern.
I'm just trying to better define (and perhaps move) that fuzzy line that seperates when it's best for the client to assert preconditions from when it's fine for the client to handle exceptions that arise when preconditions asserted by the secondary (for lack of a better term) object in use.
Considering the use of Float.parseFloat(String) , I'd just try to perform the operation and catch and handle the possible NumberFormatException. This doesn't really seem to me like a good situation for the client to assert preconditions. Doing so would involve multiple checks of the characters in the input String to ascertain in fact the String represented a parseable number. That just seems like work and why do all that work if the parseFloat method does it anyhow?
Then, consider an I/O situation where the application needs to determine if it has write access to a file. If a convenience method already existed that reported the write access privilege of the file, sure, I'd use that. If such a convenience method didn't exist, is it sloppy to just try and write to the file and catch a possible WriteNotSupportedException should one occur?
Or, let's say some application controls rods at a nuclear plant. The user inputs which rod to discard by entering a number into a TextField. The system only has rods referenced from 1 to 100 and the user enters 101. The rod controller knows that it only has rods 1 to 100 and its specification clearly states that it throws an IllegalArgumentException if the client specifies a rod that is not in the range from 1 to 100. How should the GUI handle the situation? Is it better to try and move the user specified rod and appropriately handle the possible IllegalArgumentException or should the GUI be responsible to assert the precondition that a rod from 1 to 100 is specified?
[ September 19, 2002: Message edited by: Dirk Schreckmann ]
David Weitzman
Ranch Hand

Joined: Jul 27, 2001
Posts: 1365
You're not supposed to use exceptions for flow control, but I see nothing wrong with using to catch bad input.
Float.parseFloat(String):
This situation in particular is a bit of a no-brainer. Your code shouldn't know how to parse a float and you'd probably muck up a validation implementation anyway -- catch the NumberFormatException and deal with it.
I/O situation:
If there's no method to check for access, there isn't much you can do. Here you're not using exceptions for errors or exceptional circumstances, just for flow control (instead of an if statement or perhaps just an assignment). It's sub-optimal, but you don't have any other choice.
nuclear plant:
Check it in the GUI, for a couple o' reasons.
- You can present a clearer error message.
- You'll have code to deal with the user entering non-integers anyway -- it takes nothing to check against the range on top of that.
User interfaces should be designed like objects: rather than popping up an error when the data turns out to be inconsistant, try not to let the user enter inconsistant data in the first place. It's like using 'start' and 'length' to represent a range in an object instead of 'start' and 'end'.
Less importantly:
- It's safe to assume that the number of rods (and thus the method specification) will not change in the future.
Dirk Schreckmann
Sheriff

Joined: Dec 10, 2001
Posts: 7023
Concerning changing the number of rods in the system is my next issue.
Let's say that the system now has 200 rods. I'd say that the rod controller's interface must change (or a new one with a new identity and interface must be developed) to meet the new requirements of the system and so it seems reasonable to change any clients (or create new ones) that used the original rod controller's interface. I'd also assume that, when possible, the original client should have been developed to interact with as general a rod controller as would make sense for the system being developed.
The old me would have been in error and would have tried to push the precondition assertion to the rod controller (as I've mentioned a dozen times so far). I see now that the responsibility of the GUI to instruct the user on the permissible inputs requires that the GUI know of the preconditions.
Then, I question if a model that allowed the GUI to query the rod controller for the preconditions wouldn't make some sense. The GUI wouldn't be so tightly coupled to a single type of rod controller, but could interface with any rod controller that followed this model of expressing the preconditions. Is any such model commonly used?
[ September 19, 2002: Message edited by: Dirk Schreckmann ]
Junilu Lacar
Bartender

Joined: Feb 26, 2001
Posts: 4419
    
    5

Dirk,
It's been a few months since I've read this document in preparation for the SCJD 1.4 beta but from what I can remember and understand, here's how exceptions and pre-conditions should be used:
1. Client classes should not check for runtime exceptions but should ensure that preconditions are satisfied before invoking methods.
2. Classes should ensure that preconditions are satisfied upon entry to their methods. The preconditions should be clearly defined in the JavaDoc comments. If a pre-condition is not met, a RuntimeException should be thrown.
3. Unit testing should exercise the method API and make sure that no RuntimeExceptions occur. If a RuntimeException does occur during unit testing, your client code is violating the API and needs to be modified to adhere to it.


Junilu - [How to Ask Questions] [How to Answer Questions]
Junilu Lacar
Bartender

Joined: Feb 26, 2001
Posts: 4419
    
    5

Originally posted by Dirk Schreckmann:
Concerning changing the number of rods in the system is my next issue. Let's say that the system now has 200 rods...
I would say that the model should be able to tell the GUI what the maximum number of rods were, say through a static final int MAX_RODS or a getMaxRods() method. If the Model changes the value of MAX_RODS, the GUI wouldn't have to be changed.
BTW, the Java license explicitly states "Licensee acknowledges that Licensed Software is not intended for use in the design, construction, operation or maintenance of a nuclear facility." So, you might be in violation of some precondition with this application...
Dirk Schreckmann
Sheriff

Joined: Dec 10, 2001
Posts: 7023
That was my next point.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Dirk Schreckmann:
Considering the use of Float.parseFloat(String) , I'd just try to perform the operation and catch and handle the possible NumberFormatException. This doesn't really seem to me like a good situation for the client to assert preconditions. Doing so would involve multiple checks of the characters in the input String to ascertain in fact the String represented a parseable number. That just seems like work and why do all that work if the parseFloat method does it anyhow?

What if the client could simply call a method like Float.isFloat(String)? The same Method could be used by Float.parseFloat to check the precondition. (I know, it isn't that way, but perhaps it should be?)

Then, consider an I/O situation where the application needs to determine if it has write access to a file. If a convenience method already existed that reported the write access privilege of the file, sure, I'd use that. If such a convenience method didn't exist, is it sloppy to just try and write to the file and catch a possible WriteNotSupportedException should one occur?

What if you encapsulated that code into your own convenience method?

Or, let's say some application controls rods at a nuclear plant. The user inputs which rod to discard by entering a number into a TextField. The system only has rods referenced from 1 to 100 and the user enters 101. The rod controller knows that it only has rods 1 to 100 and its specification clearly states that it throws an IllegalArgumentException if the client specifies a rod that is not in the range from 1 to 100. How should the GUI handle the situation? Is it better to try and move the user specified rod and appropriately handle the possible IllegalArgumentException or should the GUI be responsible to assert the precondition that a rod from 1 to 100 is specified?
[/QB]

IMHO it is the responsibility of the GUI to ask the model wether the value is valid.


The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
Jeremy Thornton
Ranch Hand

Joined: Feb 21, 2002
Posts: 91
Sun licence...
"You acknowledge that Software is not designed,
licensed or intended for use in the design, construction,
operation or maintenance of any nuclear facility."
bad boy.
Dirk Schreckmann
Sheriff

Joined: Dec 10, 2001
Posts: 7023
I'm sold and I've stopped my deviant runtime exception handling behavior. For the most part, at least. I'll likely still catch a NumberFormatException.
Thank you for the conversation.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
From http://c2.com/cgi/wiki?IlluminateTheMainline:
[...]the lesson here is to avoid exception handlers. It is OK to throw exceptions as long as it doesn't require your caller to catch them.
Dirk Schreckmann
Sheriff

Joined: Dec 10, 2001
Posts: 7023
corrected uri - http://c2.com/cgi/wiki?IlluminateTheMainline
Dirk Schreckmann
Sheriff

Joined: Dec 10, 2001
Posts: 7023
Nice link, thank you.
My reactions...
I'm now beginning to understand proponents of "No Checked Exceptions". I'm trying to fall inline with the school of thought that if you want to do something or tell someone else to do something, then make sure it will work first (i.e. the client should assert preconditions), and if an exception should arise, it'd better be a runtime (unchecked) exception (which means the programmer made a mistake).
I cannot say as that I'm terribly excited by the idea of reverting to the "error code" paradigm... but the author (of the first section of the Wiki page) is not suggesting that paradigm. He's suggesting that if the client cares enough to check the result of the behavior, then the client ought to take care that the thing doing the work is operating in the right environment.
So, as suggested by Ilja days ago, an isFloat(String) method would be very nice.
Dirk Schreckmann
Sheriff

Joined: Dec 10, 2001
Posts: 7023
One day then, when we're old and sitting around the JavaRanch Campfire, we'll tell stories of that interesting exception handling experiment. It was kind of neat how it allowed a programmer to consider just the preferred situation, and easily seperate out the behavior to handle the exceptional situations. But it just didn't... [thought to be continued... feel free to beat me to it.]
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Well, there are certainly situations where exceptions *are* usefull...
For example, when doing IO operations, there are many things that can go wrong - and some of them would be hard to check for upfront. It would also be quite tedious to check for these conditions every single time you read a byte from a stream... So I guess that IOExceptions are a reasonable thing to use.
As almost always, it comes down to using the right tool at the right time, so it seems to me. But I am still mulling over this, too...
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: OO precondition assertion responsibilities
 
Similar Threads
when to use assertions
Assertion doubt in K&B
Q about assertion
assertions
Unmet Precondition Failure Requirement