From: Christopher Dicely Date: 2009-03-11T23:38:31+09:00 Subject: Re: return doesn't always exit my method On Wed, Mar 11, 2009 at 6:18 AM, Benjamin Thomas wrote: > Hi, I'm new to Ruby and programming in general. > I'm coding a little script to train on multiplication tables but > something's wrong: > > If I type 'exit', the function should normally exit, via a return > statement. But this does not always happen and I really can't understand > why. I've been scratching my head for a few hours on that so I'm posting > here hoping somebody will be able to spot my obvious mistake! > > I'm trying to apply here the concept of recursion so maybe this is where > I'm messing up. > > Thanks for your input, > Ben Your intuition on where the problem is is correct. Note that when using recursion, each call to the function is a separate "layer", and calling return only jumps you out of the current layer. So if you are in the invocation of rand_multi() that you called from the top level, return will exit rand_multi() back to the top level, but if you are in an invocation of rand_multi() called from another invocation of rand_multi, return will return you from the current invocation of rand_multi() back to the calling invocation. I hope that's clear enough. If not, you can get an illustration by changing your rand_multi() method as follows: def rand_multi(call_depth=0) # <-- changed puts "entering rand_multi(#{call_depth})" # <-- added num1 = rand(10) num2 = rand(10) got_wrong = false operation = "#{num1}*#{num2}" if $tested[operation].nil? puts "creation!" $tested[operation] = 0 elsif $tested[operation] > 1 puts "need restart" rand_multi(call_depth+1) # <-- changed: forces function call again puts "returning to rand_multi(#{call_depth}" # <-- added end puts "iteration #{$tested[operation]}" print operation, " = " before = Time.now time_before = (before.min * 60) + before.sec # in case I go for a coffee :) answer = gets.chomp if answer =~ /exit/ puts "will exit now" return ##### <-- return statement does not always exit method; why?? ###### # exit elsif answer =~ /[0-9]+/ answer = answer.to_i else puts "Please enter numbers only!" rand_multi() end if answer != num1 * num2 print " [0;31m" # terminal colors puts "inside not equal" puts "No! Answer was '#{num1*num2}'" print " [0;m" sleep(1) # system "clear" got_wrong = true $tested[operation] -= 5 # give negative value rand_multi(call_depth+1) # <-- changed puts "returning to rand_multi(#{call_depth}" # <-- added elsif answer == num1 * num2 after = Time.now time_after = (after.min * 60) + after.sec answer_time = time_after - time_before print " [1;34m" puts "inside equal" puts "Yes!, you answered in #{answer_time} seconds" print " [0;m" sleep(0.3) # system "clear" if got_wrong == false if answer_time < 3 $tested[operation] += 1 # give positive value else $tested[operation] -= 1 # small penalty if answer too slow end end rand_multi(call_depth+1) # <-- changed puts "returning to rand_multi(#{call_depth}" # <-- added end end