11
$\begingroup$

This question is interesting mainly for beginners, but the answer i wrote to my own question could be also interesting for advanced users.

Introduction: While writing huge blocks of code, especially inside of a Module it can be very hard to debug your code. You quickly end up insering Print everywhere you want to check the value of a variable like:

MyModule[arg_] := Module[{a, b, c},
  a = Simplify[arg];
  Print[a];
  b = Integrate[a, {x, -\[Infinity], \[Infinity]}];
  Print[b];
  (** much more code **)
  Print[c];
]

The problem here is, that you only get the values of the variables and if you have a lot of variables you can not tell easily wich output belongs to wich variable. Counting the outputs is not an option for big modules. To match the values to the variablenames You could explicitly write the name of the variables inside the Plot, like this:

MyModule[arg_] := Module[{a, b, c},
  a = Simplify[arg];
  Print["a = ",a];
  b = Integrate[a, {x, -\[Infinity], \[Infinity]}];
  Print["b = ",b];
  (** much more code **)
  Print["c = ",c];
]

This strategy is ok, for small blocks of code, but its getting annoying very fast if you have to insert Print["variable = ", variable] everytime you want to check a variable. If you test your module maybe inside another module all the PrintOutputs will fill your notebook. So if you dont want to see the debug-outputs anymore, you would have to commend every Print, to deactivate it.

So my questions are: How can i do this more elegant more automatically? How can one switch the outputs of Print on/off? How can i get information of the variablename and its value without writing the variablename manually inside of Print?

Have a look at my answer if you want to know my solution:

$\endgroup$
4
  • 1
    $\begingroup$ Ideally, most debugging will already have been completed before you ever put individual steps, etc., inside a Module! $\endgroup$
    – murray
    Commented Feb 27, 2015 at 1:38
  • $\begingroup$ @murray thats right, i also mean modifighing, extending and understanding a module or in general a block of code. I often can not simple understand the hole code by reading it and then knowing the values of the variables during the evaluation is very helpfull. $\endgroup$
    – sacratus
    Commented Feb 27, 2015 at 1:48
  • 1
    $\begingroup$ Look at this mathematica.stackexchange.com/questions/15134/… $\endgroup$
    – faysou
    Commented Jun 6, 2015 at 16:04
  • 2
    $\begingroup$ Have you tried Assert? $\endgroup$
    – Michael E2
    Commented Jun 6, 2015 at 16:24

3 Answers 3

7
$\begingroup$

This question came up to me, when I started to use Modules in Mathematica. I first implemented a simple printfunction that can be turned on/off with a global variable:

printingEnabled = False;
Clear@print;
print[input__] := Module[{},
If[printingEnabled, Print[input]]]

So one of my problems was solved, while debuging I could set the global variable printingEnabled to True and I got the outputs produced by print[] (Not Print[]), later I could set the variable back to false and the outputs were deactivated.

Later I was getting bored of writing print["variable = ", variable] so I created a Modul that works like this:

In:

x=1;
y=3;
printD[x,y]

Out:

x = 1
y = 3

so you dont have to write the variablename inside of the printfunction anymore. It automatically looks up the variablename and adds it to the output.

If you are inside of a Module the variablenames are denoted like x$1234 but normally you are not interested in the number after the dollarsign, so I filtered this out of the variable name. Here goes my little debug-print-module:

Clear[printD]
SetAttributes[printD, HoldAll]
printD[input__] := Module[{strings, $$a},
  If[debugPrintingEnabled,
  strings = 
  StringReplace[StringTrim@StringSplit[StringTake[
  ToString[Hold[input]], {6, -2}], ","], $$a__ ~~ "$" ~~ __ :> $$a]; 
  Print @@ Flatten[Riffle[
  Table[If[StringQ[{input}[[i]]] \[And] 
     StringTrim@ToString[{input}[[i]]] == strings[[i]], {{input}[[
      i]]}, {strings[[i]] <> " = ", {input}[[i]]}], {i, 1, 
    Length[{input}]}], "\n"], 1]]
]

Its also possible to give additional information by adding strings into the argument of printD. Here goes a little example:

In:

name = "thomas";
list = {1, 2, 3};
ll = Length[list];
x$12124 = True;
printD["first name: ", name, list,
"length of the list:", ll, "localVariable x:", x$12124]

Out:

first name: 
name = thomas
list = {1,2,3}
length of the list:
ll = 3
localVariable x:
x = True

I finally created a dynamic Button to turn on/off the debug-printing:

Button[Dynamic[
  If[debugPrintingEnabled == False, , , debugPrintingEnabled = False];
  {Style["DebugPrinting is Disabled", Red, Larger, Bold], 
  Style["DebugPrinting is Enabled", Darker[Green], Larger, Bold]}〚
  Boole[debugPrintingEnabled] + 1〛],
  debugPrintingEnabled = ! debugPrintingEnabled;
]

Once you created this button you can paste it just into the notebook, where you want to use it. You dont have to set the variable debugPrintingEnabled by hand anymore.

this is how the button looks like, when debugPrinting is Enabled button, when global variable debugPrintingEnabled==False

So I am now quite satisfied with my little module, because it made my debugging process much easier and less annoying and I hope that one of you can benefit from it too.

I posted this selfanswered questing to give something back to the community for the great help I received here on my first days. See Ya.

$\endgroup$
1
  • $\begingroup$ I would make one change to handle the case when debugPrintingEnabled is not defined at all: If[debugPrintingEnabled => If[TrueQ@debugPrintingEnabled. $\endgroup$ Commented Nov 4, 2022 at 8:10
2
$\begingroup$

I sometimes use Dynamic as a debugging tool. Say there is a module which calculates some things:

Clear[a,b,c,f];
test[a_] := Module[{},
   b = f[a];
   c = a^2;];

Now if you want to peek inside the module, in real time, make one or more of the internal variables dynamic:

Dynamic[{b, c}]

At first, this just returns {b,c} but if you now invoke the function, say

test[6]

then the line below the dynamic updates automatically to show their values, in this case,

{f[6], 36}
$\endgroup$
2
$\begingroup$

This is one of the things that makes Modules hard. Composing a function from other functions is much easier to debug. I would collapse your first four lines into something like:

sinfint[arg_]:=Integrate[Simplify[arg], {x, -\[Infinity], \[Infinity]}]

Then, I'd test it:

sinfint[E^-x^2] == Sqrt[Pi]
True

No Print needed.

Make the function definition an initialization cell. Leave the test cell in as a regression test. Expand tests as needed.

Then, maybe you define

somethingelse[arg_]:=...

and a test of that. Then, maybe,

putemtogether[si_,se_]:=...

and a test. Maybe your result is then

myfunc[arg_]:=putemtogether[sinfint[arg],somethingelse[arg]]

The difficulty of writing, reading, and debugging a function grows very rapidly with the length of the function. But when you break the problem down into one-liners like this, it becomes much easier once you're used to it. And all of those tiny regression tests you accumulate as you do this come in handy later.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.