Loren on the Art of MATLAB

December 7th, 2007

Useful Debugging Commands and Tips

In my personal history using computers, I have learned to embrace debuggers to help me understand what's going on in my code.

Contents

Short List of Lesser Known Debugging Commands

Here's my short list of some useful debugging commands that might be less well known, especially for those of you who primarily use the interactive debugger as part of the MATLAB editor:

  • dbstop if error
  • dbstop if caught error
  • dbstop if warning
  • variants with specific message ID
  • dbstop if naninf

An Example

Let's set up an example so you can see what's going on. I first make sure my debugger state is all cleared up and then create a struct which I will then test to see if a particular field exists.

dbclear all
s.fred = 1;
dbtype isfieldTryE
1     function tf = isfieldTryE(s,f)
2     %ISFIELD True if field is in structure array.
3     %   F = ISFIELDTRYE(S,'field') returns true 
4     %   if 'field' is the name of a field
5     %   in the structure array S.
6     %
7     %   See also GETFIELD, SETFIELD, FIELDNAMES.
8     
9     tf = true;
10    try  
11      tmp = s.(f);
12    catch E
13        % I don't care why it failed.
14      tf = false;
15    end
16    
17    

First Experiment

What happens if I ask to see if a particular field exists, and ask for MATLAB to stop if there's an error?

dbstop if error
isfieldTryE(s,'fred')
ans =
     1
isfieldTryE(s,'freddy')
ans =
     0

What you can see is that testing for either an existing or non-existent field sails on through.

And I get the same behavior if I try to stop only for an appropriate message identifier.

dbstop if error MATLAB:nonExistentField
isfieldTryE(s,'fred')
isfieldTryE(s,'freddy')
ans =
     1
ans =
     0

Stopping for a Caught Error

To stop for an error that is caught, I use the following form of dbstop (in this case with the message identifier).

dbstop if caught error MATLAB:nonExistentField
isfieldTryE(s,'fred')
isfieldTryE(s,'freddy')
ans =
     1

Caught-error breakpoint was hit in isfieldTryE at line 11. The error was:

Reference to non-existent field 'freddy'.

ans =
     0

Now when I ask for a non-existent field, the debugger stops in the catch block. And to resume, I use

  dbcont

Common Issues

There are a few common issues that puzzle people when debugging. They include:

  • breakpoints disappearing when debugging. This is often caused by a clear all in code being run. See, for example, this post.
  • name collisions. These are caused either by using a variable name the same as a name for a MATLAB function, or having multiple functions with the same name. Using which can help you figure out what's going on if you realize there's a nameclash.
  • variables not being present. This is often an issue of not understanding scoping in MATLAB, including inputs and outputs of functions, what workspace graphics callbacks execute in, scripts versus functions.

Handy Tip

Here's a useful tip I use, for debugging, or sometimes to just find out the signature of a function. Using

dbtype 1 fileName

and you will see the first line of the file displayed. If you write your code as we tend to do at The MathWorks, the first line of a file containing functions will be the function definition line. Voila, you have the signature!

Other Debugging Gotchas and Tips?

You might find some additional debugging tips on Doug's blog.

Some people like the keyboard command or omitting terminating semicolons but I prefer to debug without editing my code, when possible.

Do you have other tips to share that you find helpful? Post them here.


Get the MATLAB code

Published with MATLAB® 7.5

12 Responses to “Useful Debugging Commands and Tips”

  1. Dan K replied on :

    Loren,
    One thing that I would love is to be able to use dbcont after correcting a problem that is nabbed by a dbstop if error. Can you explain why this isn’t possible? Also, I’d appreciate any thoughts on ways to improve the debugging of a routine which includes nested functions, since the locked name space is pretty hindering.

    Thanks,
    Dan

  2. Loren replied on :

    Dan-

    I’ve spoken to folks here about the dbcont and here’s the gist of the responses:

    Where do you continue from when you dbcont? For example,
    if an error is thrown somewhere deep in C++ code, we are not stopping until we “get back to M”. There is really no way of reliably capturing the state at that point. Or the error might have come from much deeper in M, e.g., a file that couldn’t be opened. How does MATLAB reliably go back and complete the code that errored so MATLAB can continue?

    As for debugging nested functions, depending what I am doing, if I know I need to go in there to debug, I create a struct in the parent workspace and then add fields to it as I need.

    –Loren

  3. Dan K replied on :

    Loren,
    I had assumed that a dbcont would simply try to continue by re-executing the matlab statement which threw the error in the first place. The frustration on this is that sometimes there is a lot of processing which goes into preparing for the piece of code where the error is, and one doesn’t want to have to keep going through it. In those cases, I try to set a breakpoint just before the problem so that I can do the debugging, but some of these cases are instances where it is in a subroutine that works well the first 99 times I call it, but then I call it incorrectly on the 100th time, and I don’t want to have to go through that many dbstops to try to find the one where I got taken out. Ah well, I can chalk it up to the list of “maybe some day…”. As for the nested functions, why does the name space have to be locked anyhow? I assume there is a reason for it.

    Dan

  4. Loren replied on :

    Dan-

    The nested workspace is locked down by design. We wanted no worries about guessing what identifiers meant in the workspace and did not want them to change over time. The idea with the nested function is that it should contain what it needs with it — including workspace stuff. Having items appear into the space makes it harder to know what to save, how to analyze it. If we allowed variables to be introduced, the nested function could operate differently before and after the introduction of a new variable (it used to call a function named foo, now it needs to use the variable instead, for example).

    –Loren

  5. Greg replied on :

    Another way to work around the locked-down nested workspace in the context of debugging is to declare a new variable as global before attempting to assign to it.
    Greg

  6. Kelly replied on :

    On the topic of debugging, the one gripe I have is that debugging commands can’t be used in cell mode. I assume there must be some technical reason for this, but cell mode loses some of its convenience when I have to pepper my code with return statements to track down errors or unexpected behavior.

  7. Loren replied on :

    Kelly-

    I’m not sure of the reasons. I have entered your request into the enhancement database.

    –Loren

  8. Dan K replied on :

    As long as we’re listing things that would be nice, even if they are challenging, I’d love to have some mechanism for running a function as if it were a script (i.e. assign - or copy- all values into the base workspace as you go, so that you don’t lose the state when you do hit a bug.)

    Dan

  9. Andrew Catellier replied on :

    Kelly and Loren-

    I echo that request. There is nothing more frustrating than an error without a line number. My understanding is that running code in cell mode is exactly like running it in the command line, and sure enough if you copy+paste a chunk of code into the command window, there is no line number for any errors that occur.

    Dan-

    Have you tried conditional breakpoints? You can set them in the editor window by placing a breakpoint on the line where you wish to stop, right clicking on it, clicking on “modify condition” (or similar variant), and then entering the condition on which you wish it to stop. It takes some investigation to figure out when the error happens, but I have used this technique reliably quite often.

    On a somewhat unrelated note-

    I’m using 2007b on OS X.5 - and when I’m debugging GUI code and stop debugging, all the MATLAB windows disappear…at least one other person has experienced this problem but I haven’t been able to figure out what’s going on.

    Back to topic - great post. Thanks!

  10. Loren replied on :

    Andrew-

    Good suggestion on conditional breakpoints. I know others at MathWorks are working on getting line numbers for cell mode errors.

    Please contact technical support regarding the disappearing windows.

    Thanks,
    Loren

  11. Greg replied on :

    Matlab used to stop on error, and at the command line level it still does, but for some reason it changed, and now if I insert a bad line of code into an m-file that is deep in the program, the error appears to simply pop the stack and continue, rather than stopping. To find an error, I am reduced to stepping through the program to see where it fails to go the next instruction. At the command line, I get

    >> dbstatus

    Stop if error.

    but it doesn’t do it. This started when I tried out ’stop if caught error’ etc., but now I cannot get back to the original state, much to my regret. What is happening?

    Thanks -

  12. Loren replied on :

    Greg-

    I’m guessing you have a clear all somewhere in your code. That clears the debug state as well. If that’s not the case, you probably should contact technical support for more help.

    –Loren

Leave a Reply

Wrap code fragments inside <pre> tags, like this:

<pre class="code">
a = magic(3);
sum(a)
</pre>

If you have a "<" character in your code, either follow it with a space or replace it with "&lt;" (including the semicolon).


Loren Shure works on design of the MATLAB language at The MathWorks. She writes here about once a week on MATLAB programming and related topics.

  • Jun: I totally can not believe it, Loren. You are really helpful. Thank you so much, MATLAB master!
  • Loren: Wow folks- Always lots of interest when there’s a quickie to try out! I will only make 2 general...
  • Loren: Jun- ismember is your friend here: >> [aa,ind] = ismember(Array2,Arra y1) aa = 1 1 1 1 1 1 1 ind = 1 2 1 4 4 3...
  • Dan: I like the first way better than the second way. Combining the arrays into one and running any is nice, although...
  • James Myatt: How about I = (a == 0 | b == 0); a(I) = []; b(I) = [];
  • Tunc: Hello Loren, love your blog because of such inspiring and challenging comments to such ’small’...
  • Pekka Kumpulainen: Here is my tradeoff. I usually want to keep the original variables as they are most probably...
  • Iain: Followup: Of course, to allow NaNs (counting them as non-zero): mask = (a~=0) & (b~=0); The mask says “a...
  • Matt Fig: I would usually go with something like this: y = a&b; x = a(y); y = b(y); But I was surprised to find...
  • kk: c=all([a;b]) a(c) a(b)

These postings are the author's and don't necessarily represent the opinions of The MathWorks.