Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tail recursion in ruby - what's the difference between these two implementations?

I'm new to Ruby and just started to pick up the language a couple of days back. As an exercise, I tried to implement a simple quicksort

class Sort
  def swap(i,j)
    @data[i], @data[j] = @data[j], @data[i]
  end

  def quicksort(lower=0, upper = @data.length - 1)
    return nil if lower >= upper
    m = lower
    i = 0
    ((lower+1)..upper).each do |i|
      swap(++m, i) if @data[i] < @data[lower]
    end

    swap(m, lower)

    quicksort1(lower, m -1)
    quicksort1(m+1, upper)
  end
end

Calling quicksort on say 10000 integers gives me a stack-level error. After googling, I figured out that tail-recursion isn't supported yet in Ruby (kind of). But then I found the following snippet (from here)

def qs(v)
  return v if v.nil? or v.length <= 1
  less, more = v[1..-1].partition { |i| i < v[0] }
  qs(less) + [v[0]] + qs(more)
end

Running the second snippet works perfectly well even with a million integers. Yet, as far as I can tell, there's tail recursion at the end. So what am I not understanding here?

like image 610
ajay Avatar asked Dec 08 '25 20:12

ajay


1 Answers

Neither of the methods you've shown are tail recursive (well technically the first one is half tail-recursive: the second recursive call is a tail call, but the first one is not - the second method is not tail recursive at all).

The reason that the first method overflows the stack, but the second one does not is that the first method recurses much deeper than the second (linearly instead of logarithmically) because of a bug (++m just applies the unary + operator to m twice - it does not actually do anything to m).

When given a large enough array both versions will overflow (and would do so even if ruby did perform TCO), but without the bug 10000 elements is not nearly large enough.

like image 91
sepp2k Avatar answered Dec 11 '25 13:12

sepp2k



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!