47 | Debugging 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 interactive—and symbolic—you 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 wrong—and then it’ll color it red.
Once you run a piece of code, the Wolfram Language can also often tell if things have gone obviously wrong—in which case it’ll display a message. The code here ends up, for example, asking for the first element of a length-0 list.
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]= |
In[3]:= |
Out[3]= |
As you build up functions, it’s quite common to have fragments of code that you want to test without finishing the function. You can do this by setting values of variables using With—which works like Module, except it doesn’t allow values to be reset.
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]= |
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]= |
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.
In[10]:= |
Out[10]= |
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 |
47.1Correct the program Counts[StringTake[#, 2]&/@WordList[]] for counting possible first two letters in words. »
47.3Use Sow and Reap to get a list of all cases where #/2 is used in Nest[If[EvenQ[#], #/2, 3#+1]&, 1000, 20]. »
Can I cause a problem by just trying to run a piece of code?
Not unless your code is for example set up to delete something. The Wolfram Language has protections against “obviously wrong” infinite loops and so on. If something is taking too long, you can always abort it. If you’re really concerned about resources, use TimeConstrained and MemoryConstrained.
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.
How can I tell what’s wrong when a piece of graphics is “pinked”?
It’s making a Gray code—an ordering of integers so that only one binary digit changes at each step.
- 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.