//****************************************************************************// //*************** Contracts & Exceptions - October 20th, 2017 ***************// //**************************************************************************// - So, we were talking about contracts, what it means to be a "robust" program, etc. - According to Bertrand Meyer, a CONTRACT is "defining a precondition and a post-condition for a routine that binds the routine and it's callers..." - In detail, Meyer's contracts have: - Obligations that are required from the client - Conditions that must be true before the service is used - Obligations required of the service provider - Conditions that must be true during/after the service is executed - Guarantees of the service - A definition for each method or service call - "Now, all methods have a signature, precondition, postconition, etc.; as an example, let's say we're writing the contract for a push() method:" - Signature: push(x):void - Precondition: x != null - If there's NO preconditions required, we can just say "Precondition: true" - This precondition means the CALLER needs to handle this job; otherwise, the method itself isn't required to plan for the precondition (e.g. it can just error if a null is passed in) - "If we had a way of dealing w/ nulls in the push() method, then our precondition for this method would just be 'true'" - Postcondition: top() == x, existing elements unchanged, size = size + 1 - Framing Conditions: arr, top changed - Identifies all the variables (instance or global, NOT local) that'll be affected by this method call; could be blank if the method doesn't actually change any data - Invariants: 0 <= size <= arr.length - What will always be true no matter how the method is called; again, this might be blank - Why should we do "design-by-Contract?" Because it helps to make everything certain; it gets rid of uncertainty for our methods and programs! - Makes our assumptions explicit - A GREAT way to do this is with ASSERT statement, like: assert(s != null); - "These ONLY run in debug mode, and do not affect production code" - A word of warning: NEVER have side-effects in your asserts, like "assert(s++);"; you do NOT want your test code to modify the data, only for it to change behavior in your production code - A final note: Contracts are for the EXTERNAL view of our method. We might temporarily break one of the contract rules inside of the method (e.g. resizing the array for a stack), AS LONG AS the contract is followed by the time we exit our method - Now, for error handling - From data wiz John Goodenough: "I have long advocated dealing with exception handling early in the design of a system; unfortunately, there is a natural tendency to focus on the main functional flow of the system, ignoring the impact of exceptional situations until later" - Range of consequences from errors (from acceptable to BADBADBAD): - Loss of comfort - Regulating thermostats in a house - Loss of unneeded money - Thermostats get too hot and waste money on heating - Loss of essential money - Thermostats SERIOUSLY cool down the house too much, and now we're broke - Loss of life - Our thermostat causes heat exhaustion in hospital patients - For errors, we care about: - Detection - how do I know there's an error? - Containment - how do we minimize the error's effect to just ONE area of our program? - Masking - are our errors hiding each other? - Correction - how do we fix the error? - Now, at a HIGH LEVEL: - Exceptions are deviations from the norm that we CAN expect; we try to get the application to a more predictable state, then continue (e.g. incorrect login info) - Errors are when things unexpectedly go wrong and we can do little to recover (e.g. drops phone in a pool, wire gets cut, loss of network connection, etc.) - So, why do (programming) exceptions exist at all? - In Java, exceptions are basically the program saying "I know what's wrong, but what should I do about it?"; it's a way for the part where something goes wrong to pass the issue on to a part of the program that KNOWS how to handle it - "If you're in 2110, you'll know that C doesn't have any exceptions; you have to have all your error handling code ON THE SPOT, mixed in with your business logic, instead of having all the error-checking code in one spot, like you can in Java" - 2 types of Java exceptions: - Recoverable exceptions - the system can find a way to work around it and return to the original task - e.g. FileNotFound, Checked (forced to try-catch them) vs Unchecked (can let program fail), formatting issues, etc. - Unrecoverable exceptions - the system continues running, but the user can't complete their original task - e.g. IOException caused by hardware failure, OutOfMemory, etc. - So, if the client code CAN do something about an exception, make it a checked exception! Otherwise, make it an unchecked exception - Some ANTIPATTERNS for making excpetions - things YOU SHOULD NOT DO: - Log and throw (just print the error and pass it up; you should ONLY log the error once, not multiple times) - Throwing just an "Exception" - be specific! Don't just throw a generic "Error" or "Exception" class - Similarly, CATCH a specific exception type so you can deal w/ the exception appropriately - Destructive wrapping: if you catch an exception and then have to pass it higher up, don't create a new exception and then pass that - pass the original information! Otherwise, you're losing the stacktrace! - Catch & Ignore or "return null" - if you've gotten an exception, SOMETHING'S WRONG! You NEED to fix it, not ignore it! - Unsupported operations just returning null - if you say "if (a == null) { return null}" in a method because "a" SHOULD NOT be null, don't do that! If it shouldn't be happening, throw an exception! Don't just "return null" and assume we know that means the method failed! - "Still, this is SUPER common because it's easier than actually dealing with the error, even though most people will admit it's not the best practice" - For M9, you'll need to make a Method Contract w/ a Signature, Preconditions, Postconditions, Invariants, and Frame Conditions - hop to it!