Jocellyn's Blog

Ruby function arguments explained

There are several types of variables in Ruby, each of these has a different use and different naming conventions. We will closely examine local variables and their usage in methods in this article, but just to be sure, this table should briefly summarize all Ruby variables as well as other identifiers like constants, keywords and methods names.

Type Naming convention When to use
Local variables my_hero Inside of a method or a block - they have only limited scope
Instance variables @my_hero When you want to store information for individual objects
Class variables @@my_hero When you want to store information regarding the whole Class
Global variables $MY_HERO When you want to access them globally - from multiple places
Constants MY_HERO When you want to store a data of a permanent nature
Keywords if For special tasks and contexts - these are Ruby reserved words (like `def` for method definition)
Methods names my_hero For calling or defining methods

Local variables are used to store a reference to an object. Ruby is a dynamically typed language, that means that a variable is bound only to object, not to its type (like it is in statically types languages like Haskell). The object could be a String, an Integer, a Boolean, … it doesn’t matter what type it is, a variable can store any type and then be reassigned to store something else, like here:

my_var = "this is string"
my_var = 123

It is important to understand that the variable only contains a reference to the object, not the object itself. If the object the variable references gets changed in another place, that change will be reflected when we use the variable.

my_var = "this is original string"
new_var = my_var

puts new_var
# => this is original string

my_var.replace("BOOM!")
puts new_var
# => BOOM!

This example shows the use of a String method replace, which changes the String in place. It is still the same object - a string object - but with a different value inside. On the contrary, if we would have done my_var = "BOOM!" we would have assigned to that variable a whole new object and the above example would not work. If you would like to be sure, you can inspect the object which the variable is pointing at with the object_id method.

puts my_var.object_id
#=> 70197558178100
puts new_var.object_id
#=> 70197558178100

Ok, so we discovered how local variables work, now lets take a look at how they are used inside of methods.

Arguments and parameters

When you are defining a method, the variables which are used to identify data passed in and are called parameters, but when you are calling the method you are passing arguments. It may seem like the same thing, but it is not. It doesn’t need to have the same names, the method will recognize them based on the order you passed them in.

def subtract(x,y)
  x - y
end

subtract(8,2)
# => 6

In this case the x and y in the definition are a function parameters. They are local variables which are used to store and name the objects which came into our function from the outside, so that we can refer to them inside.

8 and 2 are arguments, they are the concrete objects which we feed into our function to produce the results. Ruby will bind 8 to x and 2 to y because 8 came first and 2 came after it.

The variables defined in the method and its parameters are visible only in that method. It is called a local scope - you can not see it from the outside.

The parameters which we talked about so far were all required, which means that if you would try to call the function with a different number of arguments than it has parameters, you would get an error. There are also optional parameters, which you may or may not provide. You just need to put an asterisk in front of the parameter name *x.

def maybe_something(*a)
  puts "I got ..."
  puts a
end

maybe_something(1623)
#=> I got ...
#=> 1623

maybe_something
#=> I got ...

Another way how to make a parameter quasi optional is to state its default value. In that case, if it is provided, the one user would feed in will be used, otherwise the default value will got applied. You can do it like this: (a=4)

Be aware of the parameter assignment order - the required ones always take precedence, it doesn’t matter where they are. If you have a definition like this def method(a,b,*c,d,e) and you call it with only 4 arguments, a,b,d,e, will get assigned, but not the optional c, which will be left with nothing.

def method(a,b,*c,d,e)
  p a, b, c, d, e
end

method (1,2,3,4)
#=> 1
#=> 2
#=> []
#=> 3
#=> 4

So we have seen how methods use parameters to take an input from outside. These parameters are called arguments of a function call. If you would like to call a method without any arguments, you just type its name like this:

do_stuff

So how does Ruby tell if that is a method call or something else? Well, if it sees a word starting with lower case, like do_stuff, it firstly checks if it is not a keyword. Ruby has an internal list of all keywords so it knows how to recognize these. If not, it looks for an equal sign =. If it is there, the expression is then perceived as variable which is being assigned. If none of those cases match, it is assumed to be a method call.



Comments

comments powered by Disqus