How would one return from a place of a pure function's body using Return?

From previous answers, replies and discussions it is known, while not formally documented (even in the most recent Wolfram Language Documentation Center), that Return can be used in a two-argument form in order to exit properly from specific places of pure function bodies.

For example:

Block[{i = 0}, While[i<10, Return[{"Exit Block", i}]]; "done While"]


returns

Return[{Exit Block,0}]

while, with the two-argument form:

Block[{i = 0},
While[i<10, Return[{"Exit Block", i}, Block]]; "done While"
]


the Block is immediately exited with the expected outcome:

{Exit Block,0}.

Analogously, trying Return[..., While]:

Block[{i = 0},
While[i < 10, Return[{"Exit Block", i}, While]]; "done While"
]


works as expected, so that only the enclosing While is exited and the subsequent instruction is executed, returning:

done While

Some more tests, though, show that this concept not always works.

For example, "If" cannot be exited:

Block[{i = 0}, If[i < 10, Return[{"Exit Block", i}, If]]; "done If"]


Hold[Return[{Exit Block,0},If]]

Apparently (at least in MMA 9), the two-argument form of Return works with:

Module
Block
Do
While
For
CompoundExpression


and does not seem to work with:

If
With
DynamicModule


Does anyone have a list of valid and invalid possibilities for the second argument of Return? Is there a clear rationale distinguishing what works from what does not work?

• I would probably use Throw and Catch, with tags for clarity, instead. Sep 4, 2015 at 17:54
• In the way this is asked, this is a duplicate of this one. I'd suggest that you move the part of your question to a self-answer, showing how to return from a pure function, and assuming that the second argument of Return is a known piece of information (possibly linking to the question I mentioned). Sep 4, 2015 at 17:55
• @MichaelE2 I'd argue that using Throw and Catch is a bad style in cases when the second argument of Return can be used, from the language viewpoint. It will likely also be slower, although I did not benchmark. Sep 4, 2015 at 17:56
• @user8074 The second answer is not by me, but by Rojo. In general, you won't find a specific list of heads, because the second argument of Return can also work with user-defined heads. So, the only way to understand this to to carefully read Rojo's answer, which contains full explanation. Re: With vs Block: the reason is that With replaces the constants in code before evaluating the body, and then evaluates the code, so by the time code executes, there is no With up in the stack. With Block, it is not so, because it has to undo its dynamic environment after its body executes. Sep 4, 2015 at 18:15
• @ciao Ok, I looked again closer at Rojo's answer, and my current conclusion is that while this question is an exact duplicate of the linked question, Rojo's answer doesn't fully answer it, since Rojo focuses on user-defined symbols, rather than common built-in ones. So, the answer listing all common constructs and explaining why Return works / doesn't work for them, one by one, will be useful and will complement Rojo's answer. This is an interesting situation - personally, I'd keep this question to attract attention, and then merge with the ealier one once some answers appear here. Sep 4, 2015 at 23:23

This handling of If is more or less correct behavior. The condition evaluates to True so If exits with its second argument as the result. That second arg is Return[{"Exit Block", i}, If]. At this point the evaluator figures out there is no surrounding If from which the Return can actually return, and it (apparently) bubbles up to the top level. At worst this might be a clumsy way of handling an error state.

To see it in slightly more detail, note that the code below does not result in a value being assigned to a.

In[11]:= a =
Block[{i = 0}, If[i < 10, Return[{"Exit Block", i}, If]]; "done If"]

During evaluation of In[11]:= Return::nofunc: Function If not found enclosing Return[{Exit Block,0},If]. >>

(* Out[11]= Hold[Return[{"Exit Block", 0}, If]] *)

In[12]:= a

(* Out[12]= a *)

• "...ahndling an error state." - read while envisioning a German spy in a dimly lit Ratskeller, smoldering cigarette dangling from the corner of their rictus...
– ciao
Sep 9, 2015 at 6:44
• I guess the ahndling as been, well, ahndled. Sep 9, 2015 at 7:12