WOLFRAM

48 Debugging Your Code

48Debugging Your Code
Even the most experienced programmers have to spend time debugging their code. It’s an inevitable part of programming. But in the Wolfram Language it’s particularly easy, especially if you follow a few principles.
The first and most important principle is to try out any piece of code you write. Because the Wolfram Language is interactiveand symbolicyou can always instantly do this. So even if you just make a tiny change, run your code again, and see if your test examples still work. If they don’t, fix the code before you go on.
The Wolfram Language can sometimes tell as soon as you type something in that it’s likely to be wrongand then it’ll color it red.
A piece of code with various problems, indicated with red:
In[{}]:=
Once you run a piece of code, the Wolfram Language can also often tell if things have gone obviously wrongin which case it’ll display a message. The code here ends up, for example, asking for the first element of a length-0 list.
Something is obviously wrong when First is applied to the {} that’s produced by Cases:
In[1]:=
Out[1]=
Sometimes the Wolfram Language may not know what to do with something, but it may not be sure there’s a problem. In such cases, it’ll just leave the input unchanged and return it in a symbolic form that can later get a definite value.
Without values for a, b and c, the Wolfram Language just returns this unchanged:
In[2]:=
Out[2]=
If you generate graphics with symbolic pieces that can’t be rendered, you’ll get a pink box:
In[3]:=
Out[3]=
Use With to temporarily set m=4 to test a fragment of code:
In[4]:=
Out[4]=
When debugging takes a long time it’s usually because one’s made the wrong assumption about what one’s code is doing. And in my experience, the best way to overcome this is just to systematically analyze how the code behaves, making tables of results, generating visualizations, testing out assertions and so on.
Make plots to see what the code is doing:
In[5]:=
Out[5]=
If this code is working correctly, the result should contain every number from 0 to 2^m-1:
In[6]:=
Out[6]=
Systematically check this up to m=10:
In[7]:=
Out[7]=
Sometimes it’s not sufficient just to see the final result of a piece of code; you need to see what’s going on inside as well. You can insert the function Echo anywhere to print intermediate results or values from your code.
Echo prints values, but does not interfere with the result:
In[8]:=
1
2
3
Out[8]=
Continuously show (with a frame) the value of n reached so far:
In[9]:=
Out[9]=
Echo and Monitor just display things. If you want to actually capture intermediate results, you can do it using Sow and Reap.
Reap gives the final result together with a list of everything that was sown by Sow:
In[10]:=
Out[10]=
This sows successive values of Length[#], and reaps the results:
In[11]:=
Out[11]=
With[{x=value},expr] compute expr with x replaced by value
Echo[expr] display and return the value of expr
Monitor[expr,obj] continually display obj during a computation
Sow[expr] sow the value of expr for subsequent reaping
Reap[expr] collect values sowed while expr is being computed
48.1Correct the program Counts[StringTake[#, 2]&/@WordList[]] for counting possible first two letters in words. »
Sample expected output:
Out[]=
48.2Use Sow and Reap to find intermediate values of #1 in Fold[10#1+#2&, {1, 2, 3, 4, 5}]»
Expected output:
Out[]=
48.3Use Sow and Reap to get a list of all cases where #/2 is used in Nest[If[EvenQ[#], #/2, 3#+1]&, 1000, 20]»
Expected output:
Out[]=
Can I cause a problem by just trying to run a piece of code?
Is there a most common type of bug in Wolfram Language code?
Not really. The design of the language makes all sorts of bugs that are common in other programming languages rare. For example, “off by one” errors are common in languages where you’re always explicitly manipulating loop variables, but are rare when you’re using Wolfram Language “whole-list” functions like Table.
If I can’t figure out what’s going on, is it worth just trying random things?
If you think you’re close, it’s often not crazy to try making small random changes to code to see what happens. Since in the Wolfram Language simpler code is usually more likely to be correct, it’s not uncommon to hit the code you want by a small amount of random searching.
Is there a way to do interactive step-by-step debugging in the Wolfram Language?
Yes (at least with a native desktop interface)though it’s rarely used. Given the structure of the Wolfram Language, systematically capturing and analyzing intermediate results is almost always a better approach.
When there’s a message, how can I tell where it was generated?
Click the
In[{}]:=
next to the message, then press Show Stack Trace. This will show you the stack of functions in which the message was generated.
How can I tell what’s wrong when a piece of graphics is “pinked”?
Hover over it and you’ll see the underlying symbolic expression. Or press the + to print messages.
What is the code that makes the fractal-like graphics doing?
It’s making a Gray codean ordering of integers so that only one binary digit changes at each step.
  • If Dynamic[x] appears in a notebook, it’ll display as the dynamically updated current value of x, giving you a way to produce a real-time display of what’s going on inside a program.
  • EchoFunction, EchoTiming and EchoEvaluation are useful variants of Echo.
  • The Wolfram Language has various mechanisms for bulletproofing code. An example is Enclose and Confirm, which allows you to confirm that your program didn’t fail, and if it did, fall through to the enclosing Enclose.
  • For large-scale software development, the Wolfram Language has a built-in framework for creating and running systematic tests, with functions like VerificationTest and TestReport.
  • A major goal of good language design is to encourage people to write correct code.
Next Section