Mathematica Programming

Version 1.0

Tutorial intended for a user familiar with procedural programming and interested in learning Mathematica and functional programming and emphasizes good programming practices.

Using correct programming practices makes your code easier to debug and maintain as well as allows you to reuse code and save time. When I started programming in Mathematica, I found that Mathematica was missing some key features I had become accustomed to in procedural langauges. After some searching, I found Mathematica supports all these features or can support these features with some simple tricks.

ToDo

Need more example in Creating and accessing a database with pattern matching, like select (see Conditions on arguments) 
Add optional arguments section under Modularization

Naming Conventions

Mathematica uses 
1. Capital Letters
All built-in Mathematica commands begin with a capital letter.
2. Complete Words (mostly)
Most Mathematica commands are complete words strung together e.g. ToInversionVector.

Begin all your variable names, functions definitions, and other expression with a lower case
letter to distinguish them from Mathematica's built in commands.

Modularization

Packages and Context

From Mathematica Book
In Mathematica the mechanism of “contexts” is used to keep package symbols separate from symbols in
the main session. The basic idea is that the full name of any symbol is broken into two parts: a context
and a short name. The full name is written as context‘short, where ‘ is the backquote or grav´e accent
character, called a context mark in Mathematica.
Contexts in Mathematica work somewhat like file directories in many operating systems. You can always
specify a particular file by giving its complete name, including its directory. But at any given point, there
is usually a current working directory, analogous to the current Mathematica context. Variables that are
in the current context can be specified just by giving their short names in the same way that files in the
current working directory can be specified by just giving their short names. The global variable $Context
gives the current Mathematica context.
As is also the case with directories, contexts in Mathematica can be hierarchical. By convention, the
symbols that are created by loading a standard Mathematica package have a context whose name is
related to the name of the package. As an example, loading the package Calculus‘LaplaceTransform‘
defines the symbol Calculus‘LaplaceTransform‘LaplaceTransform, which you can then use to compute
the Laplace transform of a function.

Function Organization

This doesn't fit anywhere else so I put it here. These suggsetions come from Richard Johnson's Programming tutorial for Matlab but are general enough to be applicable here.

Structuring code, both among and within files is essential to making it understandable. Thoughtful
partitioning and ordering increase the value of the code.

Modularize.
The best way to write a big program is to assemble it from well designed small pieces (usually
functions). This approach enhances readability, understanding and testing by reducing the amount
of text which must be read to see what the code is doing. Code longer than two editor screens is a
candidate for partitioning. Small well designed functions are more likely to be usable in other
applications.

Make interaction clear.
A function interacts with other code through input and output arguments and global variables. The use of arguments is almost always clearer than the use of globals. Structures and databases can be used to avoid long lists of input or output arguments. They can be used interchangably, but subtle differences between the two in Mathematica make one more appropriate than the other in some cases. In general, structures allow direct access to data, while databases store data and use pattern matching functions to access. See sections on "Creating and accessing a database with pattern matching" and "Structured Data Types in Mathematica and using Down-values  and Up-values".

Partitioning
All subfunctions and many functions should do one thing very well.
Every function should hide something.

Use existing functions.
Developing a function that is correct, readable and reasonably flexible can be a significant task. It
may be quicker or surer to find an existing function that provides some or all of the required
functionality.

Using packages (overview)

See Michael A. Morrison's Mathematica Tips, Tricks, and Techniques: Packages

Under 3.6 the author does not include information about the MATHEMATICA_USERBASE  operating system environment variable .  It allows the user to set the base directory where user-specific files to be loaded by Mathematica  should be conventionally placed .  See  help browser entry $UserBaseDirectory.

Writing (Packages^4)

I suggest using a Mathematica notebook with the AutoSavePackage feature to write your packages. This provides a way
to include notes, examples, and other information about the package in a Mathematica notebook together with the contents of the actual package.

Roman The best description of Packages and Context I've found is Roman Maedar's section on Packages in his book Programming in Mathematica. Here is an excerpt taken from Roman E.Maeder's Mathematica's Programming Language

Package Design

see Gayley's Packaging Design Tutorial

Modularization

Good programming style suggests separating definition and implementation. The
exported functions are declared and documented. Any needed functions are
declared and imported. The package mechanism in Mathematica provides for these
features. It is explained in detail in Programming in Mathematica
(Addison-Wesley, 1991).

A Demonstration Package

Create a clean state for a new package and declare any imports.

BeginPackage["Demo`", "Needed1`"]

Create the public symbols. This is best done with a usage message.

SampleFunction::usage = "SampleFunction[n] does nothing"

Start the implementation part.

Begin["`Private`"]

All new symbols in this part will not be exported.

SampleFunction[n_] := n^3 + 2n^2 + 3n + 4

AuxFunction[m_] := something

End[]

End the package and add its context to $ContextPath.

EndPackage[]

Reading it in.

This is a machine-independent way of reading in packages.

<< Demo`

The exported function can be used outside.

?SampleFunction

The private symbols are not found.

?AuxFunction

Import of Packages: Details

Transitivity: if A` needs B` and B` needs C`, can A` use C`?

BeginPackage["A`", "B`"];

a::usage = "a in A";

Print[$Context, $ContextPath];

EndPackage[];

BeginPackage["B`", "C`"]

b::usage = "b in B"

EndPackage[]

BeginPackage["C`"]

c::usage = "c in C"

EndPackage[]

In Version 2.2, C` is not available inside the package A`. This will be fixed in the next
version.

Hidden import

BeginPackage["D1`"];

Needs["E`"]; (* hidden import *)

Print[$Context, $ContextPath];

EndPackage[];

BeginPackage["D2`"];

Needs["E`"]; (* hidden import *)

Print[$Context, $ContextPath];

EndPackage[];

$Packages

$ContextPath

In Version 2.2.0, a second attempt at hidden import fails, since the package is not
read again, and it is not put on $ContextPath. This is now fixed.

Function Overloading with Conditional Patterns

Conidtional patterns allow for flexible function overloading, i.e. functions behave differently depending on details of their arguments.

Attributes[Pair] = {Orderless}
Pair[p_List, j_] := Pair[#, j] & /@ 
        p   
Pair[n_?NumberQ i_, 
        j_] := n Pair[i, 
          j]

Pair[3  y, 3  x]

Pair[List[1, 2, 3], 3  x]

Other commonly used fuctions for testing properties of expressions,  2.3.5 and  2.3.5

It is common to use /; to set up patterns and transformation rules that apply only to expressions with certain properties.

f[x_]  :=  
      1 /; x > 0;    
f[x_]  :=  -1 /; 
        x < 0;
f[x_]  :=  1/2 /; x === 0;

Plot[f[x],  {x, -10, 10}]

The form s_ is equivalent to s:_.

function2[tree :  {a__,  b__}] := tree;

Does not pattern match

function2[1, 2]

Matches pattern  returns tree

function2[{1, 2}]

See Messages for information on giving users feedback when they enter incorrect arguments (incorrect type or number of arguments).

Messages

In addition to what I present here you might also want to study the Error handling section of Tod Gayley's PackageDesignTutorial.nb. The section covers good use of messages.

Messages  2.9  .21

Why messages? Messages give a notebook user feedback if he/she is doing something wrong. They are not intended for true error handling, see Exceptions.

Messages are useful for interacting with the user, warning the user s/he has done something wrong, while catch and throw allows a program to handle errors correctly. For example, if a user tries to divide by 0 it is useful to show the user an error message. On the other hand, if in our program we are taking averages and we do not care about division by 0 (it just means there is no data for that interval), we may want to just handle these cases by returning some value.

Creating error messages similar to Mathematica's

Sin[1, 2, 3, 4]

this is a nontrivial example of messages, which requires a good understanding of the  /; operator

computation[x___ /; Length[{x}] === 3]  := 
      Module[{}, 
  
"happy"
]

computation[1, 2, 3]

computation::"argx" = "`1` called with `2` arguments; 3 arguments \
are expected."

Message[computation::argx, 1233, 99]

We could use the definition  computation[expr____]:=Message[computation::argx,expr,Length[{expr}]].  That would cause computation[expr] with an invalid argument to evaluate to a message and the input expression would not be returned.  But we want computation to work like a built-in function so we have it post a message, and return expression passed to computation.  This can be done by putting the message in a condition as in the next line.  When this is done the condition will never evaluate to True, so the right side of the definition can be almost anything. (Text compliments of Ted Ersek)

computation[expr___] /; 
          Message[computation::"argx", computation, 
            Length[{expr}]] := "Never gets here";

This last definition is a "catch-all" that traps any cases that do not meet the conditions for the more specific function definition(s).

Now computation works like built in function, returning the unevaluted expression when given bad input.

computation[1, 2, 3, 4]

Alternatively this can be done using argument count

Preexisting error messages and error functions

Typing General:: into the Mathematica Help Browser brings up notes for the hundreds of preexisting Mathematica messages. The messages are categorized by the type of function they are associated to. These can be reused in your own functions with little effort. Because there are so many built in messages, it can be a daunting task to find a message appropriate for your function. Using a search engine to search Wolfram's Documentation site is a quick way to find the message you need. For example, if you are looking for a message to warn the user about not using a matrix, we could do a search for matrix on Wolframs message notes documentation using the following search command in the Yahoo search engine:

\(\(matrix\ \*""" 
              warning\ messages\) \*"""\ \(inurl : 
              functions\ \(hostname : documents . wolfram . com\)\)\).

This command searches the hostname "documents.wolfram.com" in any subdirectory named "functions" for any files containg the words "Warning Messages". The command may need to be modified if the documentation site ever changes.

In addition to built in error messages, Mathematica provides some functions useful for handling errors.

Argument Count

The method provided in example above is cumbersome. Mathematica has a built in argumentcountq for argument count error checking

?ArgumentCountQ

(*ClearAll[ , ,...] clear all values for the, including attributes, messages and defaults*)

ClearAll[computation]

computation[expr___] := 
      Module[{}, 
  
"happy"
] /; 
        ArgumentCountQ[computation, Length[{expr}], 3, 3]

When ArgumentCountQ test fails, a warning message is automatically generated.

computation[1, 2, 3, 4]

When ArgumentCountQ test passes, the function is evaluated.

computation[1, 2, 3]

Search path for messages

From Mathbook section 2.9.21
When you call Message, it first tries to find a message with the explicit name you have specified. If this fails, it tries to find a message with the appropriate tag associated with the symbol General. If this too fails, then Mathematica takes any function you have defined as the value of the global variable $NewMessage, and applies this function to the symbol and tag of the message you have requested.

By setting up the value of $NewMessage appropriately, you can, for example, get Mathematica to read in the text of a message from a file when that message is first needed.

Creating and Accessing a Database with Pattern Matching

Structures and databases can be used to avoid long lists of input or output arguments. They can be used interchangably, but subtle differences between the two in Mathematica make one more appropriate than the other in some cases. In general, structures allow direct access to data, while databases store data and and allow the use of pattern matching functions to access parts of the data. See section on "Structured Data Types in Mathmatica and using Down-values and Up-values" and "Modularization"->"Function Organization".

Example Database

Clear[patientDB]

\(mypatientDB\  = \ "patientDB"[

"patient record"["name"["John Doe"], "address"["Columbia, MD"], \ "phone"["555-1232"]], 
"patient record"["name"["Jim Doe"], "address"["Columbia, MD"], \ "phone"["555-1232"]], 
"patient record"["name"["Jane Doe"], "address"["Columbia, MD"], \ "phone"["555-1232"]], 
"patient record"["name"["John Smith"], "address"["Washington, DC"], \ "phone"["934-8234"]]
"patient record"["name"["John Smith"], "address"["Columbia, MD"], \ "phone"["398-1234"]]
]\)

Get all phone numbers

Cases[mypatientDB, "phone"[_], ∞]

Get all patient records with the name field "John Doe"

Cases[
      mypatientDB, "patient record"["name"["John Doe"], ___]]

While it may be tempting to use symbols for entries in your database, it is not recommended. Using a symbol for entries will cause complication when manipulating the database in a package with context (see below) or a module with local variables. For Example,

The below example demonstrates the concept as the example used in Structured Data Types in Mathematica and using Down-values  and Up-values ->Managing simple structures with down values.

(*Create a database, note that there are no downvalues assigned here*)

myDb  =  
        dbCell[deliver,  rules[op -> 3,   T -> 2]];

(*Create a function that prints the database entries, the Module command mimics package context*)

f[db_] := 
      Module[{op, deliver, T,  rules}, 
        p = {op /. (List @@ db[[-1]]), MemberQ[db,  deliver],  
            T /. List @@ db[[-1]]}]

(*function does not work because the symbols (op, deliver and T) are defined as local and do not pattern match the global symbols.*)

f[myDb]

There are two potential solutions to this problem. (1) Export all symbols used in your database in the same manner used when exporting your functions. (2) Use global symbols for all symbols in your database (see below). The problem with (1) is that databases may contain the same symbols such as unit, or have symbols generated on the fly. If the same symbols are used in different packages, they will cause shadowing problems if exported. (2) is cumbersome and likely to be overlooked when  developing new functions outside of a package, which most certainly will lead to problems when moving these functions into a package.

In addition, if you decide to use single letters as symbols in your database, exporting will not work conflicting with internal Mathematica functions and symbols. Of course, using capital uppercase symbols is contrary to the self-documenting naming conventions defined in the above.

(*Example of (2) Corrected function using the Symbol function to create the global symbol*)

f[db_] := 
      Module[{op, deliver, T,  rules}, 
        p = {Symbol["op"] /. (List @@ db[[-1]]), 
            MemberQ[db,  Symbol["deliver"]],  
            Symbol["T"] /. List @@ db[[-1]]}]

f[myDb]

To avoid such problems altogether use strings for your database patterns e.g. "db"["unit"[4]->{"entry"}].

Structured Data Types in Mathematica

Structures and databases can be used to avoid long lists of input or output arguments. They can be used interchangably, but subtle differences between the two in Mathematica make one more appropriate than the other in some cases. In general, structures allow direct access to data, while databases store data and allow the use of pattern matching functions to access parts of the data. See section on "Creating and accessing a database with pattern matching" and "Modularization"->"Function Organization".

Managing simple structures with down values

Mathematica allows for many ways to handle structured data. I present a simple method of using creating and accessing structured data without the hassle of full OOP

myline@"point1" = {1, 2}

myline@"point2" = {3, 4}

Methods

\(distance /: 
      x_[distance] /; \ \((ValueQ[x@"point1"] && 
            ValueQ[x@"point2"])\) := 
      Sqrt[\((\((x@"point1")\)[\([2]\)] - \((x@"point2")\)[\([2]\)])\)^2 + \((\((x@"point1")\)[\([1]\)] - \((x@"point2")\)[\([1]\)])\)^2]\)

myline@distance

Alternatively

\(distance[
          x_]\  /; \ \((ValueQ[x@"point1"] && 
            ValueQ[x@"point2"])\) := \ 
      Sqrt[\((\((x@"point1")\)[\([2]\)] - \((x@"point2")\)[\([2]\)])\)^2 + \((\((x@"point1")\)[\([1]\)] - \((x@"point2")\)[\([1]\)])\)^2]\)

myline // distance

While it may be tempting to use symbols to reference downvalues, it is not recommended. Using a symbol to reference a downvalue will cause complication when manipulating the database in a package with context (see below) or a module with local variables. For Example,

(*Create a structure with the following down values*)

Struct[theNumber] = 1;
Struct[theRule] = PlotRange -> {{0, 1}, {0, 1}};
Struct[theList] = {1, 2, 3};

(*Create a function that prints the structure entries,  the Module command mimics package context*)

f[struct_] := 
      Module[{theNumber, theRule, theList}, 
        p = {struct, struct[theNumber], struct[theRule], struct[theList]}; 
        Print[p]]

(*function does not work because the symbols (theNumber, theRule, and theList) are defined as local and do not pattern match the global symbols.*)

f[Struct]

There are two potential solutions to this problem. (1) Export all downvalues used in the same manner used when exporting your functions via usage messages. (2) Use global symbols for all downvalues (see below). The problem with (1) is that most structures will use the same fields such as time or size. If these symbols are used for downvalues in different packages, they will cause shadowing problems if exported. (2) is cumbersome and likely to be overlooked when  developing new functions outside of a package, which most certainly will lead to problems when moving these functions into a package.

(*Example of (2) Corrected function using the Symbol function to create the global symbol*)

f[db_] := 
      Module[{theNumber, theRule, theList}, 
        p = {db, db[Symbol["theNumber"]], db[Symbol["theRule"]], 
            db[Symbol["theList"]]}; Print[p]]

f[Struct]

To avoid such problems altogether use strings for your Structure patterns e.g. Struct["theNumber"]=1.

(Abstraction^4)

This section is primarly derived from Mathematica's Programming Language.

Abstraction refers to the act of representing essential features without including the background details or explanations. 

Abstract Data Types (ADTs) allow for handling data bits in meaningful manners.

Classes created in OOP use the concept of abstraction and are defined as a list of abstract attributes.

Abstract Data Types (taken from Roman E. Maeder Mathematica's
Programming Language)

Abstract data types are both a theoretically well-defined concept and a useful
tool for program development. Following the principles of abstract data type
design, one arrives at a clear separation of specification and implementation.

Abstract data types are defined in terms of type names, function names, and
equations. These can be realized in Mathematica very easily. The equations
become rewrite rules. The interactive nature of Mathematica makes it well
suited for rapid prototyping and testing of designs.

A detailed discussion of abstract data types in Mathematica can be found in
The Mathematica Programmer, and in Vol. 2, No. 3 of The Mathematica
Journal. Here is a short excerpt and an example.

How to Define a Data Type

Define the names of the sorts to be used.

Define the constants to be used.

Define constructors and selectors.

Write down the equations that should hold.

How to implement a Data Type

Choose a representation for elements of the sorts defined.
Usually you can use a normal expression having the name of the sort as head.
This corresponds roughly to a record in many programming languages.

Derive rules for normal forms for the data elements.
This ensures that elements are stored in a unique way. The rules are derived
from the equations and can normally be put into the constructors.

Define constructors and selectors.
These are the only operations that are allowed access to the details of the
internal representations.

Define the other operations.
An operation for which exactly one equation exists can usually be turned into
a simple rewrite rule. (Such an operation is called a derived operation.) The
variables in the left side of the rules are in the form n_type, restricting
the arguments to the correct types. Use only selectors to access parts of the
data elements on the right side of the rules.

Use overloading where appropriate.
Overloading built-in functions is most easily done by defining up-values,
rules of the form

g/: f[n_g, ...] := ...

Choose a suitable output representation of data elements.

Define automatic type conversions where useful.

An Example

This is a data type for modular numbers.

Design

Sorts:                  mod, Integer

Constants:              p

Constructors:           makemod

Selectors:              rep

Derived Operations:     Plus, Times

Equations:              Mod[ rep[ mod[n] ] - n, p ] == 0

Implementation

makemod[n_Integer] := mod[ Mod[n, p] ]

rep[ mod[n_] ] := n

mod/: m1_mod + m2_mod := makemod[ rep[m1] + rep[m2] ]
mod/: m1_mod * m2_mod := makemod[ rep[m1] * rep[m2] ]

Note that we have overloaded the built-in addition and subtraction functions.
This corresponds directly to the use of the same names in the specification.

Usage

This sets the modulus to 5 for the computations that follow.

p = 5;

This makes two modular numbers and assigns them to the variables m2 and m3.

m2 = makemod[2]; m3 = makemod[3];

Their sum is 0 (modulo 5).

m2 + m3

Their product is 1 (modulo 5).

m2 m3

OOP

In addition to abstraction, OOP provides Encapsulation, Inheritance, and Polymorphism.

Although I have not used tried using the below OOP implemetation, it appears to be the most complete avaliable.

In some cases full OOP may be an overkill

Download the required package

Download classes . m and save to the  appropriate directory.

Object-oriented Programming (taken from Roman E. Maeder Mathematica's
Programming Language)

Object-oriented programming is a programming style that is becoming more and
more popular. It promises code-reuse and easier maintenance of larger projects
than is possible with traditional procedural languages. Its use of methods and message passing
instead of procedure calls shifts the programmer's view towards close
integration of data and operations.

An interactive object-oriented language can easily be implemented in
Mathematica. The implementation is in the package Classes.m, available from
MathSource.

Objects and Classes

The first important aspect of object-oriented languages is that functions are
considered part of data. A data object "knows" which operations can be
performed on it. The functions defined for a certain type of object are part
of that object.

Thus an object is a collection of data elements and operations that act on these data elements. The operations are called methods.

Methods are usually not defined for each object separately but are collected
in a class. Objects then belong to a class from which they take their methods.

Message Passing

A uniform mechanism, called message passing, is provided for invoking the
correct piece of code, if a function is called or, as we now prefer to say, if
a message is passed to an object to execute a certain method. This viewpoint
emphasizes that it is the object's responsibility to react to a message.

Inheritance

Often a number of related data types have some common characteristics. Some
operations on them can be written in a way that does not depend on which of
the data types the operations are applied to.  Common characteristics of related data types
can then be isolated and encapsulated in a new data type. The other data types
are then made subtypes of the new type. They inherit the characteristics of
the common type, and need only implement those aspects in which they differ
from their supertype.

Thus, much of the code needs to be written only once. This saves development
time and--perhaps more important--ensures consistency, since a change needs
to be made only once, instead of being applied to several almost identical
pieces of code.

An Example

The implementation of the object-oriented system in the package Classes.m is
described in detail in Vol. 3, No. 1 of The Mathematica Journal. An updated
version of the package is available from MathSource.

Needs["Classes`"]

A class is declared with

Class[ name, superclass, instance variables, methods ]

An account has one instance variable, the balance, and methods to initialize
it and to deposit and withdraw money and to ask what the balance is.

Class[ Account, Object,
    {bal},
    {{new,      (new[super]; bal = #1)&},
     {balance,  bal&},
     {deposit,  Function[bal += #1]},
     {withdraw, Function[bal -= #1]},
     {delete,   (If[ bal != 0, Print["Remaining balance:", bal]];
                 delete[super])&}
    } ];

a1 = new[Account, 100]

Message passing is made to look like ordinary function calls. The object that
receives the message is the first argument.

deposit[ a1, 200 ]

withdraw[ a1, 500 ]

Here is a subclass of Account. It inherits most behavior. The method for
withdrawing money is overridden to check whether the balance is sufficient for
the withdrawal. If it is, we invoke the method in the superclass Account to
perform an ordinary withdrawal.

Class[ NoCreditAccount, Account,
    {},
    {{withdraw, Function[ If[ balance[self] < #1,
                              Print["cannot withdraw ", #1],
                              withdraw[super, #1] ] ]}
    } ];

a2 = new[NoCreditAccount, 1000]

withdraw[ a2, 900 ]

withdraw[ a2, 110 ]

balance[ a2]

(Exceptions^5)

The goal of exceptions (source wikipedia.org)
Exception handling is intended to facilitate use of reasonable mechanisms for handling erroneous or exceptional situations that arise in programs. Exception handling can be used to pass information about error situations that occur within library code to its users, and selectively respond to those errors. A possible role of exception handling is to allow the program to continue its normal operation and prevent crashing and displaying of cryptic error messages to the user. In many cases, it is sufficient to stop the program and produce an error report; the difference with systems that do not use exceptions to signal improper program executions is that with proper exception handling, the erroneous condition may be pointed precisely, whereas otherwise it is often detected later, making debugging difficult. Exception handling makes the signal-handling technique used in other languages obsolete.

A thrown exception may seem cryptic to an end user who has no knowledge of a functions implementation. Thus, exceptions are not a good way to present errors to users. Mathematica provides messages which are more suitable for doing this.

Playing Catch and Throw  (taken from Maeder's Programming Bits)

The rest of the section is taken from Maeder's Programming Bits with minor modifications.

Exception handling in a program requires two primitive operations: raising an exception condition and handling an exception that has been raised.
Raising an exception abandons the current flow of control and resumes execution of the program at a place where the exception is handled.

Other terms used are throw for raise and catch for handle.

In C:
setjmp(jmp_buf env) and longjmp(jmp_buf env, int val).

Functional languages: handler is wrapper around expression.

Catch[ …Throw[val,tag]…, tag ]

If an exception was thrown, Catch returns with val, otherwise with the normal result.

SML-style Raise/Handle

To get hold of tag:

Catch[ …Throw[val,tag]…, pat, f ]

returns f[val,tag] if an error is thrown and tag matches pat.

Use this to define SML-style functions:

Raise[e]

Raise exception e.

Handle[ compuation, pat :> action ]

Handle exceptions matching pat that happen during evaluation of computation and return corresponding action.

Java and newer versions of C++ offer similar features.

Implementation

`errorCookie
Raise[ error_ ] := Throw[errorCookie, error]

SetAttributes[Handle, {HoldFirst}]
Handle[try_, (pattern_ :> action_)|(pattern_ -> action_)] :=
    Catch[try, pattern, exec[pattern :> action]]

exec[rule_][ errorCookie, error_ ] := Replace[error, rule]

(Replace[e,r] is like  e/.r  but matches only the whole expression.)

Examples

Download exceptions.m and save to the appropriate directory.

Needs["Exceptions`"]

?Exceptions`*

computation

\(compuation[x___]\  := 
      Module[{}, 
 (*x\ should\ have\ 3\ arguments*) 
If[Length[{x}] =!= 3, 
          Raise["argx"]]; 
restofcompuation
]\)

Handle[ 
      compuation[1, 2, 3, 4],  "argx" :> $Failed]

example modified (argument of Raise changed from symbol to string) to handle context correctly

recip[x_]  :=  
      If[ x  ==  0,  Raise["zeroDivision"],  1/x ]

Handle[ 
      1  +  recip[2], "zeroDivision" :>  Infinity ]

Handle[ 
      1  +  recip[0],  "zeroDivision"  :>  Infinity ]

You may use patterns to handle several sorts of errors:

Handle[ recip[0],  e_  :>  Print["Error: ",  e] ]

Default handler:

recip[0]

Interfacing With Mathematica's Error Messages

Needs["Exceptions`"]

1/0

MessageList[]

Intercept[Power::infy, "zeroDivision"]

Handle[1/0, "zeroDivision" -> Infinity]

$MessageList

Useful for deeply nested errors, especially with I/O

Intercept[ OpenRead::noopen,  IOError ]

Handle[ OpenRead["nosuchfile"],  
      IOError  ->  $Failed ]

Intercepting the message is not particularly useful unless you want to change what is returned from the function when an error occurs.

Programmers' Maxim for Error Handling

Never test for an error you don't know how to handle.

More about this topic: The Mathematica Journal, Vol.7, Issue 1.

Debugging

Debugging functions in Mathematica can be quite tricky. According Dave Withoff of Wolfram Research "The next major release of Mathematica is expected to have additional features for debugging. These features are still under development and have not yet been widely used, so it is not yet known how useful these features will be in actual practice. The need for better debugging and error checking features in Mathematica has long been a concern of the programmers at Wolfram Research, and will probably continue to be so for the foreseeable future." He also offers some notes that he put together on a variety of ways of debugging Mathematica programs. 

I look forward to these additional features, but for now I debug functions using print messages or evaluting the function line by line in separate cells.

A function can be broken up for testing and debugging and put back together easily using Divide Cell (menu command) and Merge Cells (menu command). This does not work for debugging functions looping constructs within functions. (I am not sure if this is the most correct way to debug, but I have yet to find appropriate alternative.)

Using the methods discussed in the sections above to organize your code and handle errors can greatly reduce the amount of debugging. In addition to these methods, I use assert statements throughout my code to test for conditions that should hold. Because Mathematica error messages don't include a line number (with the exception of some of the syntax error messages), it is often unclear where in a function an error is occuring. And for whatever reason, when an error occurs in Mathematica, the evalution continues on the $Failed or Null return argument (not sure of any other programming languages that do this) resuling in numerous beeps as each line of the remaing code in your function fails. Using assert messages can help to track down where an error is occuring in a large function or in functions that call other functions.

Assert

Motivation

Assert statements can be used as a crude method to track down and prevent unknown states. For example, if you are calculating a speed of a car you can use an assert statement to see if the speed is resonable (between 0 and 100 mph). Assertions are widely used by programmers as a quick and effective way to detect and correct bugs. Moreover, assert statemetns add to the readability of code and help serve to document the logic or principles beneath the code. 

Mathematica is a typeless programming language. As a result, it lacks some of the built in error detection of strongly typed programs. Using assert statements, it is possible to gain the effect of type checking. Users can also add type checking to function using the methods described in the "Function Overloading with Conditional Patterns" section.

Each assert statement contains an expression that should evaluate to a Boolean True or False and an error message.

Implementation

Returns immediately when an assert condition fails printing the failed call.

SetAttributes[assert,  HoldFirst] ;

\(assert[condition_, \ errmsg_String] := \ 
      Module[{msg}, 

\ \(If[\(! ReleaseHold[condition]\), 
msg\  = \ {"assert[", 
                HoldForm[condition], ", "", 
                errmsg, ""] failed. Error message is "", \ 
                errmsg, "". "}; 

If[$Context =!= \ "Global`", \ 
\(msg\  = \ 
                  Join[msg, \ {"The error occured in the package ", \ $Context, \ "."}];\)
]; 
logMessage[
              msg]; 

Throw[error, \ 
              assert];\ 

];\)
]\)

logMessage[msg_List] := 
      Module[{y  =  StringJoin @@ (ToString /@ msg)},  Print[y]; 
        If[ValueQ[logStream], y >>> logStream ];]

Examples

Read in the package for the following examples, requires exceptions.m.

Download programmingExtras.m and save to the  appropriate directory.

<< "assert`"

?assert`*

example 1,2

x  =  {{1, 2, 3},  {3, 4},  {5, 6, 7}}

assert[MatrixQ[x], "not a matrix"]

assert[
      ValueQ[y] && y =!= {} && y =!= Null, "y is empty"]

example 3 using assert for type checking

(* matrix data gets corrupted*)

x  =  {{1, 2}, {3, 4, 3}};

assert[
      Dimensions[x] === {2, 
          2}, "Variable should be a 2x2 matrix"]

assert will write failed assert messages to file if the global variable logStream exists.

Ensure tmp file does not exist by attempting to delete.

Intercept[ DeleteFile::"nffil",  NoFile ]

Handle[ DeleteFile["tmp"],  
      NoFile  ->  "File does not exist" ]

Open a stream

logStream  =  OpenAppend["tmp"];

Attempt an assert statement that fails

assert[
      ValueQ[y] && y =!= {} && y =!= Null, "y is empty"]

Display the file's contents

!! tmp

Clear[logStream]

assert can tell you what package it failed in

Assert returns the package where the assert statement was called (using a simple hack) if provided with an optional variable.

Create a clean state for a new package and declare any imports.

BeginPackage["Demo`", "assert`"]

Create the public symbols. This is best done with a usage message.

SampleFunction::usage = "SampleFunction[n]"

Start the implementation part.

Begin["`Private`"]

SampleFunction[x_] := 
        Module[{}, 
          assert[ListQ[
              x], "SampleFunction: x isn't a list",  `c]];

End[]

EndPackage[]

Prints the assert command, the error message, and the package where the error occured.

Demo`SampleFunction[3]

Now, we know that the error occured in the Demo package, and from the error mesasge provided the error occured in SampleFunction. To find where the assert is failing, simply search the package for the error message.

References

1. Ted Ersek's Mathematica Tricks

2. Tod Gayley's PackageDesignTutorial.nb

3. Richard Johnson's Programming tutorial for Matlab

4. Roman E.Maeder's Mathematica's Programming Language

5. Roman E. Maeder's Programming Bits

6. Michael A. Morrison's Mathematica Tips, Tricks, and Techniques: Packages

7. Michael A. Morrison's Mathematica Tips, Tricks, and Techniques: Syntax

Separated by document type

Web Pages

Richard Johnson's Programming tutorial for Matlab

Notebooks

Tod Gayley's PackageDesignTutorial.nb

Roman E.Maeder's Mathematica's Programming Language

Roman E. Maeder's Programming Bits

PDFs

Ted Ersek's Mathematica Tricks

Michael A. Morrison's Mathematica Tips, Tricks, and Techniques: Packages

Michael A. Morrison's Mathematica Tips, Tricks, and Techniques: Syntax