2
$\begingroup$

Under normal conditions, evaluating something that emits a Message eg the evaluation of

1/0

that produces a Message Power::infy with text

Power: Infinite expression 1/0 encountered.

can be dealt with an expression like

Quiet[Check[1/0, $Failed]]

which returns $Failed and invokes no Message.

When evaluating Break[] 'naked' (outside any flow control loop) the front end issues a message Break::nofwd with a text

Break: No enclosing For, While, or Do found for Break[]

and returns

Hold[Break[]]    

I was expecting that after evaluating

Quiet[Check[Break[],$Failed]]

I'd obtain $Failed (without any messages generated in the process).

Instead, I get the same message Break::nofwd as before and the same output as before ie Hold[Break[]].

It is as if Check doesn't do anything when Break is its first argument.

Could someone please explain why I get this counter-intuitive result?

PS. I'm trying to pass Break[] or a function that has Break[] in its body as an argument to another function with a While loop in its body. The former function would ideally force the later function to exit the loop without any messages.

f[___]:=Break[]
SetAttributes[g, HoldAll]
g[func_] := Module[{res = Quiet[Check[func, $Failed]], j = 0},
  While[
    FailureQ[res] && j < 10,
    res = Quiet[Check[func, $Failed]];
    j++
  ];
  j
 ]

Evaluating g[f[]] returns the familiar Break::nofwd and returns Hold[Break[]]; I understand that this happens because res = Quiet[Check[func, $Failed]] gets evaluated during the initialization of Module.

$\endgroup$
  • 3
    $\begingroup$ Apparently, Break is a version of local Goto, and when there is no enclosing construct that stops it, it bubbles up, just like exceptions or aborts, except it is neither of those, so can't be caught using any of the Catch, Check, etc. So it would probably need a separate Check-like function, like e.g. this: SetAttributes[checkBreak, HoldFirst]; checkBreak[code_, failExpr_] := Module[{breakUsed = True, result}, Do[result = code; breakUsed = False, {1}]; If[breakUsed, failExpr, result]]. $\endgroup$ – Leonid Shifrin Jul 26 '18 at 10:26
  • 1
    $\begingroup$ Why does the function have to contain Break[]? If it is to force breaking the loop, then f could just return $Failed and you could just check res right before j++ using If[FailureQ[res],Break[]]. $\endgroup$ – Hector Jul 26 '18 at 10:34
  • $\begingroup$ @LeonidShifrin Thank you! Am I correct to infer that Do can be replaced with any other built-in that breaks with Break[]? $\endgroup$ – user42582 Jul 26 '18 at 12:19
  • $\begingroup$ @Hector I understand your point; in the current example what you're suggesting is actually the case! but this is just a toy example of my production code; f is a stand-in for code that uses Import to scrape html content and sometimes it returns error messages $\endgroup$ – user42582 Jul 26 '18 at 12:23
  • 1
    $\begingroup$ @user42582 Yes, can also use For or While etc. in appropriate form. I used Do since it is simple and I can easily ensure that the code is executed exactly once. In general, the need for such a construct is rather weird - I never needed that. But the observation itself, that Break[] and Continue represent another type of signals, is important. $\endgroup$ – Leonid Shifrin Jul 26 '18 at 14:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.