0

I'm currently teaching myself Ruby, via the 'Learn Ruby the Hard Way' course, and am having a problem referring to an array variable in a function.

On the section on while loops, it is required to turn a while-loop into a function, adjusting the while-loop parameters to be variables. My code:

#original while loop 
while i < 6 
  puts "At the top i is #{i}"
  numbers.push(i)
  i += 1
  puts "Numbers now: ", numbers
  puts "At the bottom i is #{i}"
end

#new function
number_array = [] 
def number_cruncher(number, cap)
  if number < cap
    puts "At the top number is #{number}"
    number_array.push(number)
    number += 1
    puts "Numbers now: ", number_array
    puts "At the bottom number is #{number}"
    number_cruncher(number, cap, number_array)
  end
end

number_cruncher(0,6)

Running this code gives a NameError, because number_array as cited in the function is an undefined local variable. I can understand that this is wrong, but I can't work out what variable scope or syntax would allow me to refer to a variable whose starting point is an empty array - except by specifying a variable 'number_array' as a parameter of the function, and then declaring number_array = [], which is functional, but seems overcomplicated.

I have researched variable scope in Ruby (here and elsewhere), but have nevertheless been unable to work this out.... Am 100% sure I am being really stupid, but help would nevertheless be appreciated!

S Spooner
  • 1
  • 2
  • Possible duplicate of [Why can't I access a local variable inside a method in Ruby?](https://stackoverflow.com/questions/10779171/why-cant-i-access-a-local-variable-inside-a-method-in-ruby) – aristotll Aug 10 '17 at 13:13

1 Answers1

1

The normal approach would just be to make this a parameter with a default value:

def number_cruncher(number, cap, number_array = [])

You're also missing the crucial return value for the recursive function. You need to do something like this:

def number_cruncher(number, cap, number_array = [])
  return number_array if number >= cap # <-- !!!!!

  puts "At the top number is #{number}"
  number_array.push(number)
  number += 1
  puts "Numbers now: ", number_array
  puts "At the bottom number is #{number}"
  number_cruncher(number, cap, number_array)
end
Tom Lord
  • 27,404
  • 4
  • 50
  • 77
  • Thanks! Having looked at it again, I now see that it also works if I specify number_array as an instance variable in all cases (somehow couldn't get this to work before). Why is that return value crucial? The function seems to work in my terminal without it. – S Spooner Aug 10 '17 at 13:25
  • Ah... It's actually working because you're *mutating the variable*! `array.push` changes the original variable's value, rather than just returning a new value. If you tried this approach using `number_array += [number]` for example, you'd see why the return value would be critical in order for this to work as a *functional* program. – Tom Lord Aug 10 '17 at 13:29
  • I'm not sure what you mean by *"also works if I specify number_array as an instance variable"*, though... Your original code would never have worked since the method only took 2 arguments, but you were calling it with 3. – Tom Lord Aug 10 '17 at 13:31
  • Yes that was a typo 3rd argument - I mean it works when I remove that third argument and use instance variables. – S Spooner Aug 10 '17 at 13:42
  • The method you give by specifying a default value doesn't work, though - gives an ArgumentError (given 3, expected 2) - is this because you can't change the default value, or is there something else I'm missing? – S Spooner Aug 10 '17 at 13:47
  • I still don't know how a local variable could work... Unless you were using a **global** variable?!?! And my code example runs fine on my machine. Please double check that you have copied it correctly, have saved the file, and are running the correct file. – Tom Lord Aug 10 '17 at 13:54
  • I apologise - when I copy and paste into a separate file, your method works, so I must have something erroneous in my document causing the error. Should have run that check, my bad! Code with instance variable is below - it generates the right results, but perhaps there is still a problem with it? – S Spooner Aug 11 '17 at 12:15
  • `@number_array = [] def number_cruncher(number, cap) if number < cap puts "At the top number is #{number}" @number_array.push(number) number += 1 puts "Numbers now: ", @number_array puts "At the bottom number is #{number}" number_cruncher(number, cap) end end` – S Spooner Aug 11 '17 at 12:17
  • Okay no I see there's a problem, because you have to reset the instance variable to [] before you recall the function. Thanks for your help and patience. – S Spooner Aug 11 '17 at 12:27
  • Yes, exactly -- You said "local variable", but are actually using an instance variable. (Which, in this context, might as well be considered a global variable.) – Tom Lord Aug 11 '17 at 15:31