From: Nasir Khan Date: 2007-04-17T05:21:09+09:00 Subject: Re: factorial in ruby ------=_Part_48850_10903427.1176754866344 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-Disposition: inline One important lesson learnt (at least by me) is that the default accumulator assignment happens *before* the Enumerable iteration. This allows the 0.fact and 1.fact to work. In fact the block is *not* even checked if the iteration does not happen, just like other Enumerable methods. So the following is possible - irb(main):002:0> (1..0).inject(1) => 1 This is cool but is it a corner case? This could lead to hard to find bugs in cases when the array or range was never meant to be accumulated (because it was empty or out of range) but there will be a return value regardless. - Nasir On 4/16/07, Jason Roelofs wrote: > > On 4/16/07, James Edward Gray II wrote: > > > > On Apr 16, 2007, at 1:58 PM, David Simas wrote: > > > > > On Tue, Apr 17, 2007 at 02:56:16AM +0900, Jason Roelofs wrote: > > >> No and most likely not. > > >> > > >> def fact(n) > > >> if n == 0 > > >> 1 > > >> else > > >> n * fact(n-1) > > >> end > > >> end > > > > > > For large enough n, this will overflow the stack. Since Ruby doesn't > > > optimize tail-recursive functions (and the above isn't tail recursive, > > > anyway), you'd better write this function as a loop (left as an > > > exercise). > > > > >> class Integer > > >> def fact > > >> (2..self).inject(1) { |f, n| f * n } > > >> end > > >> end > > => nil > > >> 0.fact > > => 1 > > >> 1.fact > > => 1 > > >> 10.fact > > => 3628800 > > >> 10_000.fact > > => 28462596809170545189064132121198688901480514017... > > > > James Edward Gray II > > > > > I knew there was a way to use #inject here, I just didn't know how. I need > to use that function more. When does this version break Ruby? > > Jason > ------=_Part_48850_10903427.1176754866344--