3
$\begingroup$

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.

$\endgroup$
  • $\begingroup$ See the doc page of Return under Possible Issues. Due to how expressions are evaluated, "function call boundaries" are not as clear as in C++. $\endgroup$ – Szabolcs Apr 21 '15 at 18:59
  • 2
    $\begingroup$ Related: (29353), (6815), (18519), (58059) $\endgroup$ – Mr.Wizard Apr 21 '15 at 19:12
  • $\begingroup$ @Mr.Wizard yes, a well traveled topic. $\endgroup$ – rcollyer Apr 21 '15 at 19:14
5
$\begingroup$

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} *)
$\endgroup$
5
$\begingroup$

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:

$\endgroup$
  • $\begingroup$ That's why Return[0, Module] didn't work when I tried it. +1 $\endgroup$ – rcollyer Apr 21 '15 at 19:32
  • 1
    $\begingroup$ @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. $\endgroup$ – Mr.Wizard Apr 21 '15 at 19:34
  • $\begingroup$ 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. $\endgroup$ – rcollyer Apr 21 '15 at 19:36
  • $\begingroup$ What does "inert" mean in this context? $\endgroup$ – Jerry Guern May 1 '15 at 5:02
  • $\begingroup$ @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." $\endgroup$ – Mr.Wizard May 1 '15 at 20:37

Your Answer

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

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