2

Please, consider the following code :

k = 0;
ret = Catch[
  Check[
    data = 1/k;
    Print[Pi] ;
    Throw[data, "RETURN"];
    , Throw @ $Failed
    ];
  , "RETURN"
  ]

In my mind, it should work this way:

  • if k = 1 (1) data = 1 (2) Check does nothing (because no message has been generated) (3) Catch catches data (4) ret = 1

  • if k = 0 (1) data = Complex Infinity (2) Check wakes up because a message has been generated (Power::infy) and throws $Failed (3) but this throw has not the tag "RETURN", therefore it is not caught by Catch and a message (Throw::no catch) is generated.

On the opposite, what happens is:

  • if k = 1 ... as expected

  • ik k = 0 ... ret = ComplexInfinity

To detect the point where I'am reasoning wrong, I added the Print command inside: Pi is printed even when k = 0 so I conjecture that Check evaluates its first argument, not returning the failexp until the whole computation has been completed. Two question:

  • is this behaviour related to the HoldAll attribute of Check ?

  • how can I break at the generation of the first message ?

mrz
  • 11,686
  • 2
  • 25
  • 81
mitochondrial
  • 1,843
  • 10
  • 16

1 Answers1

4

Check doens't stops the evaluation of its first arguments at the first message generated

Check[1/0; Print["inf"], err]
During evaluation of In[497]:= Power::infy: Infinite expression 1/0 encountered. >>

During evaluation of In[497]:= inf

err

I think you have to put a Check around every expression that could generate a message, with some convenience function

CheckAndThrow = 
 Function[expr, Quiet@Check[expr, Throw@$Failed], {HoldAll}]

(
 1 + 1;
 1/0 // CheckAndThrow;
 0^0 // CheckAndThrow;
 1 + 1
 )

Maybe someone else know a way to intercept a message generation and Throw automatically.


From the comment of @rcollyer and the links (1 and 2) provided

"Message" [handler] is invoked for every generated message and passes one argument of the form Hold[..., ...] to the handler function, with the second element set to False for quieted messages.

So, to get the effect you want, I think you can guard your code, potentially raising messages, in this way

Internal`HandlerBlock[
 {"Message", Replace[#, _[_, True] :> Throw@$Failed] &}},

 (* ... code here ... *)

]

This will throw $Failed for every not Quiet-ed message generated inside the guarded block. Because of the general convention about ...Block of code, at the end of the guarded block, this message handling behavior is discared and any previous message handling routine restored.

unlikely
  • 7,103
  • 20
  • 52