8
$\begingroup$

Procedural programming is considered a bad practice in writing Mathematica code. But for education's sake, is there any way I can do Continue using Catch and Throw?

According to WRI's documentation, the function of Break and Continue both can be achieved by using Catch and Throw. For the former one, an example is given: Catch[For[i = 1, i <= 10, i++, If[i > 2, Throw[Null]]]]; i is equivalent to For[i = 1, i <= 10, i++, If[i > 2, Break[]]]; i. For the latter, however, no example could be found. I googled for that, it seems no one asked the question. And I suspect that theoretically it can't even be done. Throw lets you quit a loop, how could it be used to jump to somewhere else in the loop as Continue does?

$\endgroup$

3 Answers 3

10
$\begingroup$

If you wrap the body of the loop with Catch, then any Throw will act as Continue:

r = 0;
Do[Catch[
   If[EvenQ[i], Throw[Null]];
   r += i
   ], {i, 10}];
r
(* Out: 25 *)

(Example taken from the documentation for Continue.)

$\endgroup$
5
  • 2
    $\begingroup$ Using Fold[]: Fold[Catch[If[EvenQ[#2], Throw[#], # + #2]] &, 0, Range[10]] $\endgroup$ Commented Jul 30, 2016 at 10:40
  • 2
    $\begingroup$ @J.M. or Fold[Catch[If[EvenQ[#2], Throw[#], # + #2]] &, Range[0, 10]] via (54784) $\endgroup$
    – Mr.Wizard
    Commented Jul 30, 2016 at 10:43
  • $\begingroup$ @Mr.Wizard, I've been using version 10 for a while and I still haven't gotten the hang of two-argument Fold[]... :D $\endgroup$ Commented Jul 30, 2016 at 10:46
  • 1
    $\begingroup$ The question has the procedural programming tag, OP specifically mentioned procedural programming, OP's example is written in procedural style, Break and Continue are fundamentally procedural constructs... just a few of the reasons why I didn't use Fold. $\endgroup$
    – C. E.
    Commented Jul 30, 2016 at 11:40
  • $\begingroup$ I know; that's why I just left a comment. It was more to demonstrate how to emulate Continue[] in a functional version of the code. In any event, I'm not likely to trade Continue[] for Catch[]/Throw[] in most cases. $\endgroup$ Commented Jul 30, 2016 at 12:04
5
$\begingroup$

This is not an answer, but an extended comment.

I don't think procedural programming in Mathematica is always to be avoided. In particular, consider the following procedural code, a minor variation of the example given for the use of Continue.

r = 0;
Do[
  If[i > 8,
    Break[],
    If[EvenQ[i], Continue[], r += i]],
  {i, 10}];
r

16

Now I write equivalent code with Catch and Throw

r = 0;
Catch[
  Do[
    Catch[
      If[i > 8,
        Throw[Null, 2],
        If[EvenQ[i], Throw[Null, 1]]; r += i],
      1],
    {i, 10}],
  2];
r

And here is the functional version based on the code proposed by J.M. and Mr.Wizard.

Catch[
  Fold[
    Catch[
      If[#2 > 8,
        Throw[#1, 2],
        If[EvenQ[#2], Throw[#1, 1], #1 + #2]], 1] &,
    Range[0, 10]],
  2]

I assert that the first example above has the great virtue of being both concise and clear, which means it is likely to be written without coding errors. Because of this and despite being tainted by procedualism, I think the first example has the best code of the three.

$\endgroup$
3
  • $\begingroup$ I agree that the first procedural snippet is the one with the clearest intent, but I don't like the word "tainted". $\endgroup$ Commented Jul 30, 2016 at 12:03
  • 1
    $\begingroup$ @J.M. That was meant to be irony. My motto is: proceduralism has its place. $\endgroup$
    – m_goldberg
    Commented Jul 30, 2016 at 17:13
  • $\begingroup$ Heads up: I just posted a rebuttal of this answer. I await your counterargument. :-) $\endgroup$
    – Mr.Wizard
    Commented Jul 31, 2016 at 8:25
1
$\begingroup$

I feel a bit uneasy about posting tangential commentary as answers but since this is too long for Comments here are my thoughts on m_goldberg's post.

I absolutely agree that procedural coding has its place in Mathematica. Nevertheless I feel that the example given is misleading. First a Do loop is already a level of abstraction above For and it is used quite often by experienced users. (It is not representative of procedural code that people typically argue against.) Second Continue[] is quite pointless in this example; one would instead just write:

r = 0;

Do[If[i > 8, Break[], If[OddQ[i], r += i]], {i, 10}]

r

The Break condition itself is also not really valid as it depends solely on the Do iterator which is never directly manipulated. A more realistic example would be a condition on r, e.g.

r = 0;

Do[If[r > 5, Break[], If[OddQ[i], r += i]], {i, 10}]

r    (* 9 *)

This could be written with NestWhile in several ways:

NestWhile[If[OddQ[++i], # + i, #] &, i = 0, # <= 5 &]

NestWhile[# + i*Boole@OddQ[i++] &, i = 0, # <= 5 &]

NestWhile[# + i*Mod[i++, 2] &, i = 0, # <= 5 &]

I do not feel that the Do/Break code is objectively clearer here.

Of course this whole example is still contrived and I one could just write Tr @ Range[1, 8, 2] or Sum[i, {i, 1, 8, 2}] in actuality.

I know it is difficult to contrive an example that is simple enough without being too simple and I do not mean to attack a straw man, but examples should still actually exemplify what they purport to if at all possible, and I feel that this one does not.

$\endgroup$
5
  • $\begingroup$ I don't have a counterargument. I agree with what you say in this post. I just don't see it as a rebuttal of my post. My point was that using procedural forms supported by Break and Continue are not improved by ignoring existence those functions and substituting Catch and Throw on the basis that they are functional. That there are better functional approches that avoid the whole issue of using Catch and Throw seems undeniable, but criticizes the OP's question on a different level than the one I was focused on. $\endgroup$
    – m_goldberg
    Commented Jul 31, 2016 at 10:36
  • $\begingroup$ @m_goldberg I think I both (1) misinterpreted your answer, and then (2) misrepresented what I meant my post to be when I called it a "rebuttal." I thought you were arguing that in this particular case Do/Break/Continue was cleaner than Fold, irrespective of the use of Throw and Catch. I thought to make that case you needed a stronger example, which is why I set about poking holes in it. But I actually think that there are times when procedural code really is "better," which again I thought you were arguing, and I was actually hoping to prod you into a better example. :^) $\endgroup$
    – Mr.Wizard
    Commented Jul 31, 2016 at 10:48
  • 2
    $\begingroup$ Sorry, some days I don't prod too good :-) $\endgroup$
    – m_goldberg
    Commented Jul 31, 2016 at 11:03
  • 1
    $\begingroup$ @m_goldberg LOL -- I hope you don't mind my laughing, because that was really funny. Probably because I can strongly identify. $\endgroup$
    – Mr.Wizard
    Commented Jul 31, 2016 at 11:07
  • $\begingroup$ To be blunt, I felt that it was a really weak demo of Continue[], but I might be biased because in all of the programming I've done, in this and other languages, I've almost always used Break[] (or its direct equivalent; sometimes all a language has is goto ;)), and I am having a hard time remembering an application where the use of Continue[] resulted in cleaner code than the Break[] equivalent. $\endgroup$ Commented Jul 31, 2016 at 11:14

Your Answer

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

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