0% found this document useful (0 votes)
5 views33 pages

L5 CSC322 Lesson 5 - Defensive Programming and Exceptions

The lecture notes cover strategies for dealing with bugs in programming, emphasizing the importance of static typing, documentation, and defensive programming. It discusses the differences between hacky coding and software engineering, as well as methods for handling exceptions and errors effectively. Additionally, it highlights the use of assertions and code contracts to improve code reliability and maintainability.

Uploaded by

Abdullah Opadeji
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views33 pages

L5 CSC322 Lesson 5 - Defensive Programming and Exceptions

The lecture notes cover strategies for dealing with bugs in programming, emphasizing the importance of static typing, documentation, and defensive programming. It discusses the differences between hacky coding and software engineering, as well as methods for handling exceptions and errors effectively. Additionally, it highlights the use of assertions and code contracts to improve code reliability and maintainability.

Uploaded by

Abdullah Opadeji
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 33

CSC322

Lecture Note 5

Dr. Victor Odumuyiwa

1
Learning Outcomes
At the end of this class, you should be able
to:
 deal with bugs,
 write defensive programs,
 handle exception.

2
DEALING WITH BUGS

3
How?

 Static typing
◦ Statically typed vs. dynamically type language
 Documenting assumptions
 Test-first programing

4
Hacking vs. Software Engineering
Hacky codes

 Writing lots of code before testing it


 Keeping all details in your head, assuming you will remember them
forever instead of writing them down in your code
 Assuming bugs will be nonexistent or else easy to find and fix

Software Engineering
• Write a little bit at a time, testing as you go
• Document the assumptions that your code depends on
• Defend your code against stupidity

5
Static checking
 Static checking: bugs are found automatically
before programs run.
 Dynamic checking: bugs are found automatically
when the code is executed.
 No checking: the language doesn’t help you find
the error at all; you have to watch for it yourself,
or end up with wrong answers.

6
How to avoid bugs
 Make bugs impossible
◦ Static-typing eliminates many runtime errors
 Localize bugs
◦ If you cannot prevent bugs, you can try to localize them to small part of the
program so you won’t have to look too hard to find the course of the bug
◦ Check the precondition(s) (defensive programming)
◦ Incremental development: build only a bit of your program at a time, and
test that bit thoroughly
 Unit testing
 Regression testing
◦ Modularity
◦ Encapsulation
 Minimize the scope of variables
 Always declare a loop control variable in the for-loop initializer
 Declare a variable only when your first need it, and in the innermost curly-
brace block that you can
 Avoid global variable
 Debug systematically

7
Two Program Aspects
 Normal program aspects
◦ Situations anticipated and dealt with in a conventional
program flow
◦ Programmed with the use of selective and iterative
control structures
 Exceptional program aspects
◦ Situations anticipated but not dealt with “in normal
ways” by the programmer
 Leads to an exception
 Recoverable via exception handling or non-recoverable
◦ Situations not anticipated by the programmer
 Leads to an exception
 Recoverable via exception handling or non-recoverable
◦ Problems beyond the control of the program
8
Example

9
Likely problems with the factorial method
1. Negative input
• -ve N leads to infinite recursion (stackoverflowException)
2. Wrong type of input
3. Wrong type of multiplication
• The operator may be redefined or overloaded to non-
multiplication
4. Numeric overflow of returned numbers
5. Memory problem
• We may run out of RAM memory during computation
6. Loss of power
7. Machine failure

10
Dealing with the factorial method problems
 Problem1could be dealt with as a normal program
aspect
 Problem 2 is prevented by the analysis of the
compiler (static typing)
 Problem 3 is prevented by the compiler
 Problem 4 could be dealt with by the use of another
type than long
 Problem 5 could be foreseen as an anticipated
exception
 Problem 5 and 7 are beyond the control of the
program
 In extremely critical application, it may be necessary
to deal with (handle) problem 6 and 7

11
How are errors handled?
 Ignore
◦ False alarm
 Report
◦ Write a message on the screen or in a log - Helpful
for subsequent correction of the source program
 Terminate
◦ Stopped the program execution in a controlled and
gentle way – Save data, close connections
 Repair
◦ Recover from the error in the running program –
Continue normal program execution when the error
is solved.

12
Where are errors handled?
 Handle errors at the place in the program
where they occur
◦ If possible, this is the easiest approach
◦ Not always possible nor appropriate
 Handle errors at another place
◦ Along the calling chain
◦ Separation of concern

13
How to avoid bugs
 Make bugs impossible
◦ Static-typing eliminates many runtime errors
 Localize bugs
◦ If you cannot prevent bugs, you can try to localize them to small part of the
program so you won’t have to look too hard to find the course of the bug
◦ Check the precondition(s) (defensive programming)
◦ Incremental development: build only a bit of your program at a time, and
test that bit thoroughly
 Unit testing
 Regression testing
◦ Modularity
◦ Encapsulation
 Minimize the scope of variables
 Always declare a loop control variable in the for-loop initializer
 Declare a variable only when your first need it, and in the innermost curly-
brace block that you can
 Avoid global variable
 Debug systematically

14
Defensive Programming
 Protect your code from bugs

 Use assertion

 “An assertion is code that’s used during development—


usually a routine or macro—that allows a program to
check itself as it runs. When an assertion is true, that
means everything is operating as expected. When it’s
false, that means it has detected an unexpected error in
the code” (Code Complete).

15
Assertions
 “An assertion usually takes two arguments: a boolean
expression that describes the assumption that’s
supposed to be true and a message to display if it isn’t.”

 “Assertions are normally compiled into the code at


development time and compiled out of the code for
production.”

 “During production, they are compiled out of the code


so that the assertions don’t degrade system
performance.”

(Code Complete)

16
Assertions contd.
 Never use assertion to test conditions that are external
to your code such as the existence of files, the
availability of the network etc.
 Assertions test the internal state of your program to
ensure that it is within the bounds of its specification.
 Assertion failure therefore indicate bugs.
 External failures are not bugs, and there is no change
you can make to your program in advance that will
prevent them from happening.
 External failures should be handled using exceptions.

17
Code Contract
 “Code contracts provide a way to specify preconditions,
postconditions, and object invariants in your code”.
 The classes for code contracts can be found in the
System.Diagnostics.Contracts namespace.

 Contract.requires()
 Contract.ensures()

18
The benefits of code contracts include the following:
 Improved testing: Code contracts provide static contract
verification, runtime checking, and documentation generation.
 Automatic testing tools: You can use code contracts to
generate more meaningful unit tests by filtering out
meaningless test arguments that do not satisfy preconditions.
 Static verification: The static checker can decide whether
there are any contract violations without running the
program. It checks for implicit contracts, such as null
dereferences and array bounds, and explicit contracts.
 Reference documentation: The documentation generator
augments existing XML documentation files with contract
information. There are also style sheets that can be used with
Sandcastle so that the generated documentation pages have
contract sections.

19
EXCEPTION

20
Exception
 Object-Oriented Exception handling
◦ Representation of an error as an object
◦ Classification of errors in class inheritance
hierarchies

21
An error as an object
 Encapsulation of relevant error knowledge
◦ Place of occurrence (class, method, line number)
◦ Kind of error
◦ Error message formulation
◦ Call stack information
 Transportation of the error
◦ From the place of origin to the place of handling
◦ Via a special throw mechanism in the language

22
The hierarchy of Exceptions in C#
(Exception class)
 ApplicationException
◦ Your own exception types
 SystemException
◦ ArgumentException
 ArgumentNullException
 ArgumentOutOfRangeException
◦ DivideByZeroException
◦ IndexOutOfRangeException
◦ NullReferenceException
◦ RankException
◦ StackOverFlowException
◦ IOException
 EndOfStreamException
 FileNotFoundException
 FileLoadException

23
try-catch statement
 It allows us handle certain exceptions
instead of stopping the program

try{
}
catch(exception-type-1 name){
}
Catch(exception-type- 2 name){
}

24
25
 When the CLR encounters an
exceptional code, it halts execution and
displays information about the error that
occurs. This information is known as a
stack trace.

26
Propagation of exceptions in C#
 Handling exception outside of where they
occur.
 Handling exception where methods are
invoked.

Check code

27
Try-catch-finally
 At least one catch or finally clause must
appear in a try statement.
 The finally clause will be executed in all
cases, both in case of errors, in case of
error-free execution of try part, and in
cases where control is passed out of try
by means of a jumping command.

28
Raising and throwing exceptions in C#
A Throw statement

Definition of the exception class

29
Recommendations about exception handling
 Control flow
◦ Do not use throw and try-catch as iterative or conditional control
structures
◦ Normal control flow should be done with normal control structures
 Efficiency
◦ It is time consuming to throw an exception
◦ It is more efficient to deal with the problem as a normal program
aspect-if possible
 Naming
◦ Suffix names of exception classes with “Exception”
 Exception class hierarchy
◦ Your own exception classes should be subclasses of
ApplicationException
◦ Or alternatively (as of a more recent recommendation) of Exception

30
 Exception classes
◦ Prefer predefined exception classes instead of
programming your own exception classes
◦ Consider specialization of existing and specific
exception classes
 Catching
◦ Do not catch exceptions for which there is no cure
◦ Leave such exceptions to earlier (outer) parts of the
call-chain
 Burying
◦ Avoid empty handler exceptions – exception burying
◦ If you touch an exception without handling it, always
re-throw it.

31
 “Use try/catch blocks around code that can
potentially generate an exception, and use a finally
block to clean up resources, if necessary. This way,
the try statement generates the exception, the
catch statement handles the exception, and the
finally statement closes or de-allocates resources
whether or not an exception occurs”.
 “In catch blocks, always order exceptions from
the most specific to the least specific. This
technique handles the specific exception before it
is passed to a more general catch block”.

Source: http://msdn.microsoft.com/en-us/library/seyhszts.aspx

32
Resources
 http://www.codeproject.com/Articles/300
9/C-Documenting-and-Commenting
 https://msdn.microsoft.com/en-
us/library/ms182532.aspx
 https://msdn.microsoft.com/en-
us/library/dd264808.aspx

33

You might also like