[Python-ideas] A Continuations Compromise in Python

Steven D'Aprano steve at pearwood.info
Sun May 3 17:29:28 CEST 2009


On Mon, 4 May 2009 12:34:53 am Steven D'Aprano wrote about removing 
tail-recursion:

> In this case, the speed-up could (in principle) be by up to a factor
> of five or so, not a mere couple of percent. 

Sorry, that "factor of five" is probably bogus. I got that for some 
comparisons between recursion and iteration, but the speed difference 
is probably not relevant to the sort of tail call optimizations we're 
discussing. I will *not* defend my suggestion of 5x faster, however, on 
the basis of my Towers of Hanoi test, I think 2x faster is conceivable.


I found Guido's recent blog post of tail call optimization:

http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html

Worthwhile reading. Also read the commenters: they make some interesting 
points, such as that tail call optimization is a general technique 
applicable to more than just recursion.

Guido's largest objection to TCO is that it ruins nice stack traces when 
you get an exception. I must admit I've never understood this argument. 
Perhaps I'm missing something, but I've never considered the stack 
trace you get in recursive functions useful. Here's an example:

>>> def spam(n=0):
...     if n == 10: raise ValueError(
...     'Nobody expects the Spanish Inquisition!')
...     spam(n+1)
...
>>> spam()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in spam
  File "<stdin>", line 3, in spam
  File "<stdin>", line 3, in spam
  File "<stdin>", line 3, in spam
  File "<stdin>", line 3, in spam
  File "<stdin>", line 3, in spam
  File "<stdin>", line 3, in spam
  File "<stdin>", line 3, in spam
  File "<stdin>", line 3, in spam
  File "<stdin>", line 3, in spam
  File "<stdin>", line 2, in spam
ValueError: Nobody expects the Spanish Inquisition!

To me, all those identical "line 3, in spam" lines are just noise. They 
get in the way of a nice stack trace! What is Guido seeing that I'm 
not? Hopefully he isn't counting them by hand to see how deep he got 
into the recursion!

I wish there was a way to tell Python to just throw that white noise 
away and give me the sort of stack trace I get from a loop function. 
(It's not so bad when there only ten lines, but when there's 1000, you 
might very well fill your xterm's buffer and lose valuable history.)

>>> def ham(n=0):
...     while n < 0:
...             n += 1
...     raise ValueError('Nobody expects the Spanish Inquisition!')
...
>>> ham()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in ham
ValueError: Nobody expects the Spanish Inquisition!

Which of course illustrates the point that Guido's recommendation to 
re-write the recursion as an iterative loop by hand will have the same 
effect on the stack trace as iteration already does. I haven't heard 
anyone argue that stack traces in a while or for loop should show you 
the entire history of the loop, so I wonder why recursive calls should 
be treated as sacrosanct?

(I have nothing to say about Guido's other arguments against TCO at this 
point, but my silence should not be interpreted as agreement.)



-- 
Steven D'Aprano



More information about the Python-ideas mailing list