Message Boards Message Boards


Has the behavior of $RecursionLimit changed?

Posted 8 months ago
5 Replies
7 Total Likes

The tutorial Controlling Infinite Evaluation says:

When the Wolfram Language stops without finishing evaluation, it returns a held result. You can continue the evaluation by explicitly calling ReleaseHold.

It includes this minimal example:

In[1]:= x = x + 1

... $RecursionLimit: Recursion depth of 256 exceeded.

Out[2]= 255 + Hold[1 + x]

It appears this is no longer the behavior in version 11.3. Instead of evaluating to a partial result when $RecursionLimit is reached, the original expression wrapped in Hold is returned. Actually, to be more precise, when I evaluate x=x+1 on a fresh kernel I get Hold[x+1], but if I set $RecursionLimit to any valid number I get Hold[x=x+1].

In contrast, the behavior of $IterationLimit is as documented.

The Mathematica StackExchange discussion for reference:

5 Replies
Posted 8 months ago

I think this is a case where the functionality intentionally changed, and the documentation wasn't entirely updated to properly reflect the changes.

I've reported this, and if it turns out my guess was incorrect I'll let you know.

This is correct: the change was effectively intentional.

In slightly more detail, changes were made in handling of RecursionLimit overflows in order to improve the ability of the Mathematica kernel to return to a reasonable place rather than get lost in further recursion (as was happening in multiple-recursion situations). The change in form of the eventual result was a not necessarily intended byproduct.

Whether one views that new form in and of itself as better or worse, it was needed in order to achieve the bigger goal of repairing a severe problem with multiple recursion.

I'm sorry, Daniel, I may have replied to Kyle when I meant to reply to you. I'm new to the Wolfram Community website and likely clicked the wrong button. Please see below.

@RobertJacobson, I saw the questions but I don't have answers. There were a few changes made to address issues with deep recursion over the past nine or so years. The example x=x+1 has been through a few changes going back to 2009.

You are correct that deep iteration is unchanged (so far as I am aware).

Thank you for such a detailed and helpful response. Are you able to tell me when this change was introduced? (It must have been <= v11.1.0.0.)

As far as I can tell, $IterationLimit is unaffected. Is this correct? E.g., this still works:

In[1]:= f[n_]:=f[n+1]                                                           
In[2]:= f[1]
$IterationLimit::itlim: Iteration limit of 4096 exceeded.
Out[2]= Hold[f[4096 + 1]]
In[3]:= ReleaseHold[%]
$IterationLimit::itlim: Iteration limit of 4096 exceeded.
Out[3]= Hold[f[8191 + 1]]

If $IterationLimit is unaffected and $IterationLimit and $RecursionLimit now behave differently, then:

  1. It is now important for programmers to know when they will encounter one versus the other, which is not at all clear from the documentation even if it is updated to reflect the new behavior. The obvious answer for experts is, "tail-recursion," but experts are presumably already writing tail-recursive expressions. (*ahem*)
  2. The resulting expression obtained from hitting the $RecursionLimit during evaluation is no longer very meaningful. Applying ReleaseHold only repeats the original computation that has failed already. Considering the change, I intend to put in a feature request that expressions that hit the $RecursionLimit during evaluation return $failed. This change would have the additional advantage of further distinguishing between $IterationLimit and $RecursionLimit.

I'm happy to send the documentation bug reports and the feature request through the correct channels, but I'm interested in the answers myself.

Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
or Discard

Group Abstract Group Abstract