5

I need to test some complicated conditions to calculate a Return value. But MMa doesn't let you Return[] from anywhere the way C++ does. The structure of my Module is similar to this:

foo[x_] := Module[{},
 Do[
  If[x == (n^2), Return[0]];
  If[x == (n^4), Return[1]],
  {n, 1, 5}];
 Return[2]];

If Return[] actually Return'd, foo[4] would return 0, but instead it returns 2.

Is there a way to do a return from an arbitrary place in the code?

I know that effete programmers will dislike my program structure, but I'm asking how to force the Return[], not how to restructure the program.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
Jerry Guern
  • 4,602
  • 18
  • 47

2 Answers2

6

As pointed out in the comments, Return only exits from the inner most construct. So, even though foo[4] hits the True clause in the first If statement, that only exits Do. Instead of using Return, use Throw/Catch, e.g.

bar[x_] := Module[{$myTag},
     Catch[
      Do[ 
       If[x == (n^2), Throw[0, $myTag]];
   If[x == (n^4), Throw[1, $myTag]]
       ,
       {n, 1, 5}
      ];
      Throw[2, $myTag]
  ,
  $myTag
 ]
];

Note, I use $myTag to insulate Catch against other throws. Then,

bar /@ {1, 2, 4, 7, 8, 16}
(* {0, 2, 0, 2, 2, 1} *)
rcollyer
  • 33,976
  • 7
  • 92
  • 191
6

If your Module were not inert you could use the second parameter of Return as follows:

foo[x_] :=
 Module[{n},
   Do[
    If[x == (n^2), Return[0, Module]];
    If[x == (n^4), Return[1, Module]],
    {n, 1, 5}
   ];
   Return[2]
 ]

foo[4]
0

Alternatively you could Return to CompoundExpression if you eliminate it from within the Do loop:

foo[x_] :=
  (
   Do[
    {If[x == (n^2), Return[0, CompoundExpression]],
     If[x == (n^4), Return[1, CompoundExpression]]},
    {n, 1, 5}
   ];
   Return[2]
  )

foo[4]
0

For a more complete explanation see:

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • That's why Return[0, Module] didn't work when I tried it. +1 – rcollyer Apr 21 '15 at 19:32
  • 1
    @rcollyer I'll admit it threw me at first too but I avoid null Module constructs like the plague so I hadn't come across it before. – Mr.Wizard Apr 21 '15 at 19:34
  • I see them occasionally, mostly on here, though, as most feel the need to put some sort of scoping construct around code when simple parentheses will do. – rcollyer Apr 21 '15 at 19:36
  • What does "inert" mean in this context? – Jerry Guern May 01 '15 at 05:02
  • @Jerry I meant that Module[{}, body] is simply body (in nearly all circumstances) therefore Module is inert as in "having no inherent power of action, motion, or resistance." – Mr.Wizard May 01 '15 at 20:37
  • @Mr.Wizard Serious question. Is there some deep design logic behind the way Return[] is designed to work in MMa that I'm not sophisticated enough to see, or are there some genuinely stooopid design elements in MMa? The solutions above worked, but they seem like elaborate contortions to accomplish something Return[] should have been designed to do in the first place. Am I just not seeing the hidden beauty? – Jerry Guern Aug 11 '15 at 18:38
  • @Jerry I assume you are speaking of the need to bluntly specify Module or CompoundExpression for it to work right? As I see it that is a consequence of the way Mathematica evaluates definitions and the need for disambiguation. It is not apparent to Mathematica that you want Return to apply to your user-defined foo and not e.g. Do, and even if it were Return[0, foo] does not work as Rojo explains in the linked Q&A. Return as implemented has a few special uses that make it important, (continued) – Mr.Wizard Aug 11 '15 at 21:31
  • @Jerry however, I suppose a different Return could also be useful. Perhaps we can even implement one ourselves? Would you describe the exact behavior that you would like to see from Return? Would it always be used with Set or SetDelayed (DownValues) definitions for example? – Mr.Wizard Aug 11 '15 at 21:33
  • 1
    @Mr.Wizard, I suspect that a response you'd find useful is a bit beyond my MMa sophistication. I couldn't make sense of rcollyer's Answer about tags at all. I got your code suggestion to Return stuff the way I wanted it to, but I still didn't understand your clarification about inert Modules or why my Module was inert or what the CompoundExpression thing did. I asked my Aug 11 question in the Comment above because there's SO much in MMa's design that seems to senseless and needlessly complicated to me that I wonder if there's some overarching method to WR's madness that I'm just not seeing.. – Jerry Guern Aug 15 '15 at 20:25