1

I'm currently learning Ruby and hit some behavior I don't quite understand. In the example code below, I have two until loops, each in their own method. When executing until_test it outputs an loop of 10 20 10 20 10 20 forever but when executing second_until_test it behaves as I expect it to, outputing only 10 20. It seems that for some reason the way the code is now, I'm not able to change variables passed as parameters. I know the answer to this is likely very simple but I've failed to figure it out or find the answer on here after searching a while. What is the proper way to pass parameters successfully as I'm trying to do in until_test?

Thanks in advance!

def until_test
    num = 10
    until num == 20
        do_this(num)
    end
end

def second_until_test
    num = 10
    until num == 20
        puts num
        num = 20
        puts num
    end
end

def do_this(variable)
    puts variable
    variable = 20
    puts variable
end
Eric Marchese
  • 404
  • 4
  • 10
  • possible duplicate of ['pass parameter by reference' in Ruby?](http://stackoverflow.com/questions/161510/pass-parameter-by-reference-in-ruby) – jcm May 29 '15 at 22:13

4 Answers4

0

I fixed you problem here:

def until_test
    num = 10
    until num == 20
        num = do_this(num)
    end
end

def second_until_test
    num = 10
    until num == 20
        puts num
        num = 20
        puts num
    end
end

def do_this(variable)
    puts variable
    variable = 20
    puts variable
 return variable
end

until_test
dpctrey
  • 34
  • 3
0

Your problem here is namespace... In second_until_test, num is valid for the method, so it will be changed inside the untill loop.

In until_test, you are passing num as an argument to another method, which will not directly change the passed object, unless you assert num to the return value of the method:

def until_test
  num = 10
  until num == 20
    num = do_this(num)
   end 
 end

def do_this(variable)
  puts 20
  variable = 20
  # this method has to return the value for num
  variable # or return variable, or return 20...
end

TLDR: until_test's num does not change value, that's why it will loop forever.

Ninigi
  • 1,311
  • 12
  • 19
0

The other answers are correct. The reason you get a forever loop in until_test is because your do_this method doesn't return your modified variable. Calling puts doesn't return the value of the parameter passed, but nil, so that means, what you are assigning num is nil rather than the desired modified output :)

Anyways, just sharing an another way to kill the cat :)

In ruby, there is something that you call an instance variable. Any modification to the variable that is made within your script, be it other methods, will change the value of the variable. It can be simply declared by prepending an @ to the variable. You can also use $ to make it global. Thanks Eric for pointing that out hahaha...

Implementing this on your code will look like this:

@num
def until_test
    @num = 10
    until @num == 20
        do_this(@num)
    end
end

def second_until_test
    @num = 10
    until @num == 20
        puts @num
        @num = 20
        puts @num
    end
end

def do_this(variable)
    puts variable
    variable = 20
    @num = variable
    puts variable
end
  • Aren't global variables prefixed with `$`? I guess what you're saying is an instance variable (`@`) is essentially acting like a global variable if it's defined before and outside of the methods using them? Thanks for the response, btw. I'd give you an up vote but don't have enough points yet! – Eric Marchese May 30 '15 at 15:20
  • Oopps hahaha... thanks for the correction.. Yes, I mean an instance variable :) Anyways, a global variable will work the same :) Lemme edit that hahaha – Jason Adrian Bargas May 30 '15 at 23:10
0

The selected answer is the best one, although Jason gives an alternative technique.

To clarify on Jason's answer, an instance variable is accessible to all the methods defined in an object's method, including nested methods.

class Dog
  def dog_things
    @dog = "Rex"
    def bark
      puts "#{@dog} goes 'bark, bark'"
    end
    bark
  end
end

Dog.new.dog_things
=> "Rex goes 'bark, bark'"

And in Ruby, even if you haven't defined any classes or objects, you are nonetheless, always in an object. It's called main and it's an object of the Object class.

puts self
=> main
puts self.class
=> Object

The difference between instance and global variables is that if you define a class, the instance variable you set before creating the class is not available in the class (although it can have another instance variable with the same name).

Global variables, however, once defined, are accessible everywhere, in all classes and outside classes.

SteveTurczyn
  • 36,057
  • 6
  • 41
  • 53