Search code examples
rubymethodsruby-on-rails-3.2pass-by-referenceargument-passing

How to make a Ruby method to pass output parameters (change the value of referenced arguments)?


I'm trying to make a method with output arguments in ruby.

I read differents posts here and here about the discussion of wether ruby pass its arguments by-value or by-reference and

I undersand that on a strict sens, Ruby always pass-by-value, but the value passed is actually a reference. Reason why there is so much debate on this.

I find out that there are several ways to change the value of the referenced variable. For instance with the replace method when its an Array, a Hash or a String, or merge! when it's a hash.

I found out that with integer, I can change and pass the value outside my method without any special method use.

My question is about other objects. For instance I want to retrieve the 'id' attribute of an object, and the object reference itself :

  class RestaurantController < ApplicationController
    def pizza_to_deliver(pizza_name, id_of_the_order, pizza)

      # pizza to eat
      pizza = Pizza.where(:name => pizza_name).first

      # unknown pizza
      return false if pizza.nil?

      # first customer order about this pizza
      id_of_the_order = Orders.where(:pizza_id => pizza.id).first

      true
    end
  end

my_pizza_name = 'margerita'
My_order_id = nil
my_pizza = nil

my_restaurant = RestaurantController.new

if my_restauant.pizza_to_deliver(my_pizza_name, My_order_id, my_pizza) then
  puts "Pizza to deliver : #{my_order_id}"
  rex_dog.eat(my_pizza)
end

How to make this works ? (order_id and my_pizza remains with nil)


Solution

  • Ruby has only pass by value, just like Python and Java. Also like Python and Java, objects are not values directly, and are manipulated through references.

    It seems you already understand how it works -- assigning to a local variable never has any effect on a caller scope. And to "share" information with the caller scope other than returning, you must use some method on the object to "mutate" the object (if such a method exists; i.e. if the object is mutable) that is pointed to by the passed reference. However, this simply modifies the same object rather than giving a reference to a new object, which you want.

    If you are not willing to return the value, you can pass a mutable container (like an array of one element) that the called function can then mutate and put whatever in there and have it be seen in the caller scope.

    Another option is to have the function take a block. The function would give the block the new value of pizza, and the block (which is given by the caller) can then decide what to do with it. The caller can pass a block that simply sets the pizza in its own scope.