tags:

views:

298

answers:

7

In MATLAB, how do you tell where in the code a variable is getting output?

I have about 10K lines of MATLAB code with about 4 people working on it. Somewhere, someone has dumped a variable in a MATLAB script in the typical way:

foo

Unfortunately, I do not know what variable is getting output. And the output is cluttering out other more important outputs.

Any ideas?

p.s. Anyone ever try overwriting Standard.out? Since MATLAB and Java integration is so tight, would that work? A trick I've used in Java when faced with this problem is to replace Standard.out with my own version.

+2  A: 

If you have a line such as:

foo = 2

and there is no ";" on the end, then the output will be dumped to the screen with the variable name appearing first:

foo =

     2

In this case, you should search the file for the string "foo =" and find the line missing a ";".

If you are seeing output with no variable name appearing, then the output is probably being dumped to the screen using either the DISP or FPRINTF function. Searching the file for "disp" or "fprintf" should help you find where the data is being displayed.

If you are seeing output with the variable name "ans" appearing, this is a case when a computation is being done, not being put in a variable, and is missing a ';' at the end of the line, such as:

size(foo)

In general, this is a bad practice for displaying what's going on in the code, since (as you have found out) it can be hard to find where these have been placed in a large piece of code. In this case, the easiest way to find the offending line is to use MLINT, as other answers have suggested.

gnovice
+5  A: 
MatlabDoug
+1: MLINT works well for a missing ';', but I guess it wouldn't help if an errant DISP was the problem.
gnovice
A: 

You'll need to traverse all your m-files (probably using a recursive function, or unix('find -type f -iname *.m') ). Call mlint on each filename:

r = mlint(filename);

r will be a (possibly empty) structure with a message field. Look for the message that starts with "Terminate statement with semicolon to suppress output".

weiyin
+3  A: 

Ooh, I hate this too. I wish Matlab had a "dbstop if display" to stop on exactly this.

The mlint traversal from weiyin is a good idea. Mlint can't see dynamic code, though, such as arguments to eval() or string-valued figure handle callbacks. I've run in to output like this in callbacks like this, where update_table() returns something in some conditions.

uicontrol('Style','pushbutton', 'Callback','update_table')

You can "duck-punch" a method in to built-in types to give you a hook for dbstop. In a directory on your Matlab path, create a new directory named "@double", and make a @double/display.m file like this.

function display(varargin)
builtin('display', varargin{:});

Then you can do

dbstop in double/display at 2

and run your code. Now you'll be dropped in to the debugger whenever display is implicitly called by the omitted semicolon, including from dynamic code. Doing it for @double seems to cover char and cells as well. If it's a different type being displayed, you may have to experiment.

You could probably override the built-in disp() the same way. I think this would be analagous to a custom replacement for Java's System.out stream.

Needless to say, adding methods to built-in types is nonstandard, unsupported, very error-prone, and something to be very wary of outside a debugging session.

Andrew Janke
+1  A: 

You could run mlint as a function and interpret the results.

>> I = mlint('filename','-struct');
>> isErrorMessage = arrayfun(@(S)strcmp(S.message,...
      'Terminate statement with semicolon to suppress output (in functions).'),I);
>>I(isErrorMessage ).line

This will only find missing semicolons in that single file. So this would have to be run on a list of files (functions) that are called from some main function.

If you wanted to find calls to disp() or fprintf() you would need to read in the text of the file and use regular expresions to find the calls.

Note: If you are using a script instead of a function you will need to change the above message to read: 'Terminate statement with semicolon to suppress output (in scripts).'

KennyMorton
+2  A: 

I like the idea of "dbstop if display", however this is not a dbstop option that i know of.

If all else fails, there is still hope. Mlint is a good idea, but if there are many thousands of lines and many functions, then you may never find the offender. Worse, if this code has been sloppily written, there will be zillions of mlint flags that appear. How will you narrow it down?

A solution is to display your way there. I would overload the display function. Only temporarily, but this will work. If the output is being dumped to the command line as

ans = 
      stuff

or as

foo = 
      stuff

Then it has been written out with display. If it is coming out as just

stuff

then disp is the culprit. Why does it matter? Overload the offender. Create a new directory in some directory that is on top of your MATLAB search path, called @double (assuming that the output is a double variable. If it is character, then you will need an @char directory.) Do NOT put the @double directory itself on the MATLAB search path, just put it in some directory that is on your path.

Inside this directory, put a new m-file called disp.m or display.m, depending upon your determination of what has done the command line output. The contents of the m-file will be a call to the function builtin, which will allow you to then call the builtin version of disp or display on the input.

Now, set a debugging point inside the new function. Every time output is generated to the screen, this function will be called. If there are multiple events, you may need to use the debugger to allow processing to proceed until the offender has been trapped. Eventually, this process will trap the offensive line. Remember, you are in the debugger! Use the debugger to determine which function called disp, and where. You can step out of disp or display, or just look at the contents of dbstack to see what has happened.

When all is done and the problem repaired, delete this extra directory, and the disp/display function you put in it.

woodchips
A: 

Andrew Janke's overloading is a very useful tip the only other thing is instead of using dbstop I find the following works better, for the simple reason that putting a stop in display.m will cause execution to pause, every time display.m is called, even if nothing is written.

This way, the stop will only be triggered when display is called to write a non null string, and you won't have to step through a potentially very large number of useless display calls

function display(varargin)
builtin('display', varargin{:});
if isempty(varargin{1})==0
keyboard
end
Geoffrey

related questions