7

In a module I'm writing I have (for the development and testing phases) lots of Print["Messages"]. I have two questions:

  1. What is the best practice to print such "debugging" messages?
  2. Is there a way to call the module such that the messages will NOT be printed? For example, when calling the module from another module, I would like not to see all the output of the first one.
Dror
  • 12,174
  • 21
  • 90
  • 160
  • 2
    In v.8, there's also `Assert` which is similar in that it prints message on test failure, and can be turned off – Yaroslav Bulatov Feb 25 '11 at 21:30
  • @Verbeia Yes, that's right ... I just thought the two questions are so close it would be beneficial to have them merged and have all answers at the same place. Whether that one is merged into this one or the reverse it doesn't matter ... – Szabolcs Jan 02 '12 at 11:25
  • @Szabolcs see message for you in chat – Verbeia Jan 02 '12 at 11:39

5 Answers5

12

I like to always keep global variables prefixed with the $, and functions without the prefix, so I'd write:

debugPrint[args___] := $debugPrintFunction[args]

$debugPrintFunction = Print[##] &

Then you can just use debugPrint exactly like you'd use Print now. When you want to get rid of the debugging messages, you just unset the variable:

$debugPrintFunction = .

There are some advantages to doing it this way. One is that you can use Block to switch the debugging on and off locally:

In[1]:= foo[x_] := (debugPrint[x]; x+1)

In[2]:= foo[3]
3
Out[2]= 4

In[3]:= Block[{$debugPrintFunction}, foo[3]
Out[3]= 4

You can even locally make $debugPrintFunction do something else, like Sow values for a Reap to pick up, or direct the debugging messages somewhere else, like

strm = OpenWrite["your/log/path/here", InputForm];
Block[{$debugPrintFunction = Write[strm, ##]},
  foo[3]];
Close[strm];

Used judiciously, the dynamic scoping provided by Block allows the use of global variables in a relatively safe and controlled way.

Pillsy
  • 9,781
  • 1
  • 43
  • 70
8

My older code uses a method like Pillsy describes.

More recently I've use a head that doesn't normally have any rules, like:

...
debugPrint[expr]
...

and then have a second function:

Attributes[PrintDebug]={HoldAll}

PrintDebug[expr_] := Block[{debugPrint = Print}, expr]

Then when I want to see the debugging output I can wrap PrintDebug around the input:

PrintDebug[MyFunction[1,2,3]]

or, more frequently as

MyFunction[1,2,3] // PrintDebug

since I find the postfix form easier to add/remove and better leaving the focus on the main function.

Brett Champion
  • 8,497
  • 1
  • 27
  • 44
6

I usually install a verbosing option into my functions, that can be turned on/off if necessary for debugging. Note that by specifying the default for Verbose inside the function you can control whether the information is printed or not.

In[5]:= func1[arg_, opts___] := Module[{verbose},
   verbose = Verbose /. {opts} /. {Verbose -> True};
   If[verbose, Print["Verbosing function1: arg is ", arg]];
   arg
   ];

func2[arg_, opts___] := Module[{verbose},
   verbose = Verbose /. {opts} /. {Verbose -> False};
   func1[arg, Verbose -> verbose]
   ];

In[7]:= func1[123]

During evaluation of In[7]:= Verbosing function1: arg is 123

Out[7]= 123

In[8]:= func2[456]

Out[8]= 456

In[9]:= func1[123, Verbose -> False]

Out[9]= 123

In[10]:= func2[456, Verbose -> True]

During evaluation of In[10]:= Verbosing function1: arg is 456

Out[10]= 456

Of course one can elaborate this example to be comply with the programming standards of Mathematica (e.g. adding the Options[func1, Verbose -> ...] header and then accessing the Options from inside the function, but this is not the point here.

István Zachar
  • 1,343
  • 2
  • 13
  • 31
3

Yet another possibility:

debugPrint::msg = "Debug message: `1`";    
debugPrint[msg_] := Message[debugPrint::msg, msg]

Use the function like this:

debugPrint["hello"]

Turn off or on messages like this:

Off[debugPrint::msg]

On[debugPrint::msg]
Szabolcs
  • 24,728
  • 9
  • 85
  • 174
0

For me, since M has no build-in debugger to speak of, I waste 50% of my time just in debugging, which could have been saved if there was a debugger. 50% of my development code is Print statements, since without these, I'll be lost finding where an error is coming from. (this is bad also, since too much print messages in the code, makes it hard to see the algorithm sometime, it gets in the way, but can't remove it, since I might needs it later on).

I find it amazing that such a powerful and flexible computational tool like M, still has a relatively less advanced development environment. When I am using Matlab, It takes me few seconds to find where a bug is, using the debugger.

Someone might say use Workbench for debugging. I tried to use to debug a Manipulate demo, and I can't figure it out. Too complicated to use. M needs a simple easy to use debugger build-in (in the notebook itself, not a separate program), and with line numbers!

Ok, Given the above introduction :), this is what I do myself in response to your question:

  1. have different level of debug messages. coarse level, and detailed level. Coarse level prints only a message when it enters a function and when it exists the function.

  2. I have a button on the UI to use to turn on/off debugging (if you are doing UI based program, else it will be in the code).

  3. Use a separate debug function, where debugging message go through before being printed. In there, you can add time stamp to each message and such before printing (can also control if you want messages to go to text file, from one place). Rest of your code, just calls this debug function with the message to print. I print everything now to console, not to current notebook.

  4. Each debug message with have the function name that called it at its start.

  5. If you want to control debugging at the module level, what I do, it simply make a local debug flag inside the Module, and turn that on/off each time I want to debug that one specific module. This local debug flag takes over the setting of the global debug flag. This way, I can debug just one module if I want, and not the rest of the code.

There are many other ways to customize all of this. But I found that if I spend more time early on to make a good debugging message system, it help allot in finding bugs when needed.

Here are some useful link

http://reference.wolfram.com/mathematica/guide/TuningAndDebugging.html

workbench debugger (if you can figure how to use to debug Manipulate and Dynamics, please let me know)

http://www.wolfram.com/products/workbench/features/debug.html

Nasser
  • 12,849
  • 6
  • 52
  • 104
  • 3
    Just to clarify, Mathematica *does* have a built-in debugger, where you can set breakpoint, step into code, etc. Though it's a bit inconvenient to use, it is there. `Evaluation -> Debugger` – Szabolcs Jan 02 '12 at 10:02
  • @Szabolcs, yes, I know about that one. But is it really practically usable? I spend may be 2 hrs on it the other day, and could not even figure how to use it at all to debug my notebook Manipulate. At the end, I just gave up, and back to printing messages :) – Nasser Jan 02 '12 at 10:16
  • 2
    Many people might come across this question and answer, and I thought it is misleading for them to state that there is no debugger. It is true I don't use it much, and that it's not terribly practical, but I do use it occasionally. – Szabolcs Jan 02 '12 at 10:49
  • 1
    A succinct description of the usage of the built-in debugger can be found in my answer here: http://stackoverflow.com/a/8363520/615464 – Sjoerd C. de Vries Jan 02 '12 at 15:21
  • @SjoerdC.deVries, thanks you! will give this another look. I could need all the help debugging. – Nasser Jan 02 '12 at 21:14
  • @Nasser If debugging is such a significant component of your workflow (in terms of time/effort), it may indicate that you are not taking full advantages of what Mathematica offers: functional programming (many small functions, composition), immutability (very few assignments, not much state), pattern-matching (type-checking for function arguments). Make each of your functions small and transparent, and don't be afraid of having many small functions. There were several threads here at SO with good suggestions on debugging. I find it particularly useful to have aggressive (zero-tolerance) ... – Leonid Shifrin Jan 03 '12 at 10:16
  • @Nasser ... approach to errors: set up error-checking through patterns for all (or most) of my internal functions, and throw an exception when the error happens. I described this and gave a toy example here:http://stackoverflow.com/questions/6560116/best-practices-in-error-reporting-mathematica/6563886#6563886 . This saves me perhaps 80-90 % of my debugging time. Currently, extended debugging time usually is an indicator for me that some functions are not well-designed: overly complex and have to be split into smaller ones. – Leonid Shifrin Jan 03 '12 at 10:21