I've written a function CheckReturn
that attempts to behave just like Check
, except that it returns immediately if a message is generated. Also, if Quiet
wrappers are used external or internal to CheckReturn
, the behavior is consistent with how Check
works. The code is given at the end. Here are some examples:
CheckReturn[1/0; Print[2], $Failed]
Check[1/0; Print[2], $Failed]
Power::infy: Infinite expression 1/0 encountered.
$Failed
Power::infy: Infinite expression 1/0 encountered.
2
$Failed
Notice that using CheckReturn
, 2 was not printed. So far so good. Now, let's use an external Quiet
:
Quiet @ CheckReturn[1/0; Print[2], $Failed]
Quiet @ Check[1/0; Print[2], $Failed]
$Failed
2
$Failed
In both cases the message is detected and failure expression is returned, but CheckReturn
returns immediately without printing 2. Similarly, if we use an internal Quiet
:
CheckReturn[ Quiet[1/0]; Print[2], $Failed]
Check[ Quiet[1/0]; Print[2], $Failed]
2
2
In both cases the internal Quiet
is respected, and the message is not detected. CheckReturn
has the option "CheckQuietedMessages"->False
. If we set this option to True
, than the internal Quiet
is disregarded:
CheckReturn[ Quiet[1/0]; Print[2], $Failed, "CheckQuietedMessages"->True ]
Power::infy: Infinite expression 1/0 encountered.
$Failed
Just like Check
has a 3-arg version where explicit messages can be specified, the same is possible with CheckReturn
:
CheckReturn[ 1/0; Print[2], $Failed, Power::infy ]
Power::infy: Infinite expression 1/0 encountered.
$Failed
Finally, if messages are turned off, than CheckReturn
ignores them as well:
Off[Power::infy]
CheckReturn[ 1/0; Print[2], $Failed, Power::infy]
Check[1/0; Print[2], $Failed, Power::infy]
2
2
Note that I didn't consider parallel behavior. Here is the code:
SetAttributes[CheckReturn,HoldAll]
Options[CheckReturn]={"CheckQuietedMessages"->False};
CheckReturn[body_,return_, OptionsPattern[]] := Module[{handler,flag},
With[{stack = If[TrueQ@OptionValue["CheckQuietedMessages"], _, quietStack[]]},
handler[Hold[mess_Message, True]]:=Throw[$Failed,flag];
handler[Hold[mess:Message[mn_,___], False]] /; quietedMessageCheck[HoldForm[mn],stack] := Throw[
Hold[mess],
flag
]
];
Catch[
Internal`HandlerBlock[{"Message",handler},body],
flag,
(ReleaseHold[#];return)&
]
]
CheckReturn[body_, return_, m_, OptionsPattern[]]:=Module[{pred,handler, flag},
pred = messagePredicate[m];
(
With[{stack = If[TrueQ@OptionValue["CheckQuietedMessages"], _, quietStack[]]},
handler[Hold[mess:Message[mn_?pred,___], True]] := Throw[$Failed,flag];
handler[Hold[mess:Message[mn_?pred,___], False]] /; quietedMessageCheck[HoldForm[mn],stack] := Throw[
Hold[mess],
flag
]
];
Catch[
Internal`HandlerBlock[{"Message", handler}, body],
flag,
(ReleaseHold[#];return)&
]
) /; pred=!=$Failed
]
SetAttributes[{messagePredicate, messageRules}, HoldAll]
messagePredicate[m_] := Replace[
messageRules[m],
r:Except[$Failed] :> Function[Null,ReplaceAll[HoldForm[#], r], HoldAll]
]
messageRules[MessageName[General, m_]] := HoldForm[MessageName[_,m]] -> True
messageRules[MessageName[t_, m_]] := HoldForm[MessageName[t,m]] -> True
messageRules[m:{__MessageName}] := messageRules /@ Unevaluated[m]
messageRules[m_String] := Replace[
Hold[m] /. $MessageGroups,
{
Hold[mn:{__MessageName}] :> messageRules[mn],
_ :> (Message[CheckReturn::mgre, m]; $Failed)
}
]
messageRules[m_] := (Message[Message::name, HoldForm[m]]; $Failed)
quietStack[] := Alternatives @@ (Stack/.Internal`QuietStatus[])[[1,All,1]]
quietedMessageCheck[m_HoldForm, stack_] := Count[
First[MessageList /. Internal`QuietStatus[]] /. m -> True,
{True, stack}
] > 0