5
$\begingroup$

To save time when debugging with Print statements, I'd like to define a function -- call it PrintVal -- that prints both the name and value of a variable defined locally within the calling function. The function would be called with a single argument, which would be the name of the variable in question (expressed in the form of a string). To provide a concrete example, if fooVar is a variable defined as local to a module within the calling function, and if the current value of fooVar is 9, then

PrintVal[ "fooVar" ]

should print

fooVar = 9

The new function would thus have the same effect as including the statement

Print[ "fooVar = ", fooVar ]

directly within the calling function itself, but without the need to type the variable name twice, to include the equal sign, and (most important from a time-saving perspective) to include some other formatting stuff that I haven't mentioned here (because it's not relevant to the part I'm struggling with).

Although there may well be an embarrassingly simple solution that I don't know enough to have thought of, after a considerable amount of experimentation, documentation-reading, and web-searching, I've been unable to find one. With apologies in advance if I'm missing something obvious, I'd be very grateful to anyone who might provide a (detailed and concrete) solution.

Many thanks!

$\endgroup$
3
  • $\begingroup$ Is it necessary for the argument to be passed as a String? Could you use PrintVal[fooVar] instead if the output were the same? $\endgroup$
    – Mr.Wizard
    Nov 6, 2014 at 9:07
  • 1
    $\begingroup$ Mr. Wizard: No need for the argument to be specified as a string. Indeed, specifying the argument to PrintVal without having to include the quotes will save me even more time, and the solution you've provided below seems to work perfectly! $\endgroup$ Nov 6, 2014 at 22:34
  • $\begingroup$ I'm glad I could help, and thanks for the Accept. :-) $\endgroup$
    – Mr.Wizard
    Nov 7, 2014 at 1:21

1 Answer 1

5
$\begingroup$

Here is a method that is not exactly to your specification but which may serve you anyway. It uses a Symbol argument. Because a Symbol is passed it is automatically modified by Module and does not need the guesswork of $ModuleNumber etc. but it does need string conversion and cleanup.

SetAttributes[printVal, HoldFirst];

printVal[s_Symbol] := 
  Print @ Row[{StringTrim[SymbolName@Unevaluated@s, "$" ~~ DigitCharacter ..], s}, "="]

An example:

b = "Fail!" (*this should not print!*);

Module[{b},
 b = RandomInteger[9, 3]^2;
 printVal[b];
 b
]

b = {16, 4, 36}

{16, 4, 36}

Regarding why naive attempts fail you must consider the mechanism of Module; only visible (explicit) Symbols in the body are substituted by localized equivalents. A String that is later converted to a Symbol is not included in this localization:

b = "Fail!";

Module[{b},
 b = RandomInteger[9, 3]^2;
 Print[b];
 Print[Unevaluated@b];
 Print[Symbol["b"]];
]

{81, 64, 36}

b$2061

Fail!

Note that Symbol["b"] evaluates to the global b rather than the localized b$2061.

$\endgroup$
6
  • 1
    $\begingroup$ You may add .. to "$" so it works well in DynamicModule too. One should be careful where it is called there anyway. $\endgroup$
    – Kuba
    Nov 6, 2014 at 10:01
  • 1
    $\begingroup$ @Kuba I hadn't thought about DynamicModule. (Thanks for reminding me.) I don't know how this would behave there; I need to think about that. $\endgroup$
    – Mr.Wizard
    Nov 6, 2014 at 10:02
  • 1
    $\begingroup$ Printing should be held till DM content is displayed. DynamicModule[{b}, { Slider[Dynamic[b, (b = #; printVal[b];) &]], printVal[b]; SymbolName[Unevaluated@b], Button["print b", printVal[b]] }] $\endgroup$
    – Kuba
    Nov 6, 2014 at 10:07
  • $\begingroup$ As noted above, in the quick tests I've just run, @Mr.Wizard's solution seems to work perfectly for me. I'm also grateful to Kuba for his comment. Many thanks to both of you! $\endgroup$ Nov 6, 2014 at 22:46
  • 1
    $\begingroup$ I tried this solution on a Manipulate Control variable, and it gave unexpected results ("b\$" instead of "b"). The reason was that these variables use two "\$"s and not just one. The easy fix is to use ("\$"..) instead of just "\$" in the String pattern. $\endgroup$ Jan 23, 2019 at 20:26

Your Answer

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

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