I know that Check[expr,failexpr]
is a mechanism to catch messages. The problem with it is that if a message is generated within expr
, Check[expr,failexpr]
will return failexpr
, and the return value of expr
will be lost. Sometimes messages are just warnings and do not imply that the return value of a computation will be garbage. So what I want is a mechanism to detect messages within an expression without losing the return value of the expression. Through this mechanism I intend to Print
some additional information to the screen, that will allow me to debug the Message. How can I do this?
-
$\begingroup$ Incidentally have you seen these?: (8215), (20367) $\endgroup$ – Mr.Wizard Oct 17 '14 at 22:33
One can define a dynamic environment where Message
will be overloaded. Here is one way:
ClearAll[withMessageDetection];
SetAttributes[withMessageDetection, HoldAll];
withMessageDetection[code_] :=
Internal`InheritedBlock[{Message},
Module[{inMessage, tag},
Unprotect[Message];
(call : Message[args___]) /; ! TrueQ[inMessage] :=
Block[{inMessage = True},
Sow[{args}, tag];
call
];
Protect[Message];
Reap[code, tag, #2 &]
]
]
For example:
withMessageDetection[Range[10][[15]]]
During evaluation of In[676]:= Part::partw: Part 15 of {1,2,3,4,5,6,7,8,9,10} does not exist. >>
(* {{1,2,3,4,5,6,7,8,9,10}[[15]],{{{Part::partw,15,{1,2,3,4,5,6,7,8,9,10}}}}} *)
If you just want to print the information, you can use Print
instead or together with Sow
and Reap
.
EDIT
A different version addressing the spec clarification in comments:
ClearAll[withMessageDetectionAlt];
SetAttributes[withMessageDetectionAlt, HoldAll];
withMessageDetectionAlt[code_, msgCode_] :=
Internal`InheritedBlock[{Message},
Module[{inMessage, messageWasIssued},
Unprotect[Message];
(call : Message[args___]) /; ! TrueQ[inMessage] :=
Block[{inMessage = True},
messageWasIssued = True;
call
];
Protect[Message];
messageWasIssued = False;
With[{result = code},
If[messageWasIssued , msgCode];
result
]
]
];
For example:
withMessageDetectionAlt[Range[10][[15]], Print["Message issued!"]]
During evaluation of In[1423]:= Part::partw: Part 15 of {1,2,3,4,5,6,7,8,9,10} does not exist. >>
During evaluation of In[1423]:= Message issued!
(* {1,2,3,4,5,6,7,8,9,10}[[15]] *)
-
$\begingroup$ The interface I had in mind was something like
withMessageDetection[expr1, expr2]
, which always returns the result ofexpr1
, and evaluatesexpr2
(ignoring its return value, butPrint
insideexpr2
still has effect) if and only if Messages are generated insideexpr1
. $\endgroup$ – becko Oct 17 '14 at 14:45 -
$\begingroup$ @becko I think, this spec is underdesigned. What if more than one message is generated during the evaluation? Do you want to evaluate
expr2
on every generated message? Also, you will probably need to somehow pass the information about the currently generated message to theexpr2
. One way of doing this would be to use the syntaxwithMessageDetection[expr1, {msginfo_Symbol,expr2}]
, where you refer to whatever symbol you pass asmsginfo
, insideexpr2
, if you need that. Another way would be to makeexpr2
a function of those message parameters. Let me know which you'd prefer. $\endgroup$ – Leonid Shifrin Oct 17 '14 at 15:08 -
$\begingroup$
expr2
gets evaluated only once afterexpr1
has completed, if and only ifexpr1
generates one or more messages.expr2
doesn't need to know the specific messages generated byexpr1
(those will get printed to$Messages
, so I will see them there if I have to). $\endgroup$ – becko Oct 17 '14 at 21:44 -
A simple way would be to assign the value of expr
to a variable and then return that variable after printing the messages. For example:
info::values = "n was `` and d was ``";
Module[{n, d, v}
, n = 100
; d = 0
; Check[v = n / d, Message[info::values, n, d]; v]
]