Intro to Functions

Posted by Berin Loritsch Fri, 22 Aug 2008 11:58:00 GMT

When you are just writing quick scripts, you can use Ruby all you want and be happy. However, there comes a point where you have to do the same thing in a bunch of places. Functions are a way to organize the logic in your code so that you can re-use it in more than one place. I’ll introduce how to do math at the beginning, but functions aren’t only for numbers as we will show later.

Doing Some Math

As long as you are working with numbers, you will have to remember some symbols. In your math text books you will see symbols that just don’t exist on keyboards and requires different key combination to make them show up. The good news is that the conventions for replacing mathematical symbols in code is pretty standard across languages. You only have to learn them once, which helps.

  • + addition
  • - subtraction
  • * multiplication
  • / division
  • % modulus
  • ^ exponent
  • () group expressions

Math expressions are performed in algebraic order. In short, that means that expressions are evaluated in the reverse order from what I listed. Parentheses first, exponents next, then multiplication, division and modulus, finally addition and subtraction. Just to make it clear, look at the following code:

puts 4 + 5 * 6
# 34

puts (4 + 5) * 6
# 54

puts 4 + (5 * 6)
# 34

It’s a good habit to use parentheses to make things clearer. There’s a few more symbols that allow you to do bit manipulation, but then I have to explain the math behind it. Let’s focus on this level of math for now. Let’s say we want to do a little trigonometry and calculate the area of a circle. The mathematical formula for the area of a circle is πr2. So how do we get a hold of the value of π? There is a Ruby module called Math that has the value of π and other more advanced functions.

Ok, so how does the expression look like in Ruby?

radius = 5

puts Math::PI * (radius ^ 2)
# 15.707963267949

I added the parentheses to make it clearer that the exponent (raising to the power of two) comes first. So what if we wanted to reuse this function anywhere? We would have to create a function to do it. It’s pretty easy, and you will use the same construct in another post when we talk about creating our own methods. Let’s create our function:

def area radius
    Math::PI * (radius ^ 2)
end

So what’s going on here? The word def is a Ruby keyword that tells Ruby that you are creating a function. After that, is the name of the function. Finally we have the list of parameters. A parameter is a name we give to a value that you pass to the function. Basically, the function is going to do something with that value—even though it doesn’t know what the value is first. The next line bears some explaining.

Functions can return a value, which is usually their whole point. However, we don’t see any words that say “return this”. It’s probably the most unintuitive thing you’ll run into with Ruby, but the last expression in a function is the value that’s returned. It’s a carryover from Smalltalk, and once you understand that it becomes a little more understandable. If we had one more line that just had the number 2 on it, then the function would always return the number 2—which is wrong for what we want. What some people do to make things a bit clearer is to use the keyword return . That keyword is designed for letting you leave a method early for some cases, but it works just as well. It’s probably not a bad habit as other languages require you to use it. The method would now look like this:

def area radius
    return Math::PI * (radius ^ 2)
end

The keyword end is something we saw already when we were doing loops in the last lesson. This keyword is used to end any block, so you will use it a lot.

Not All Functions Are for Math

I introduced functions with math because that’s where the idea came from. But most problems don’t require the use of heavy math. Ruby isn’t designed to be a math engine anyway. Just for fun, let’s create a function that will turn a number into words—Japanese words to be exact. It’s only fitting as Ruby came from Japan after all. Just to save us some work, we’ll limit ourselves to the range from 0 to 99. To do that we need to use an if statement. The if statement let’s us do something if it is true, but skips the code inside if it is not true. We also want to raise an issue so that the calling code knows that they asked something we can’t deliver. The keyword is raise , which is rather convenient. You can “raise” any object, but we will just use a string. The code looks like this:

if not (0..99).include? number
    raise "We can only translate numbers between 0 and 99" 
end

I’ll include the solution below, and just expound on things in comments. Your job is to expand the method to do up to 999, or to change it to another language. I’m using Japanese partly because it’s easy to do with code. Other languages have more exceptions.

def to_japanese(number)
    #
    # Protect our method from trying to work on numbers
    # it doesn't support
    #
    if not (0..99).include? number
        raise  "We can only translate numbers between 0 and 99" 
    end

    #
    # Keep it simple, use the variations of four and
    # nine that work in the tens column as well as
    # the ones column.  These are the numbers from
    # zero to nine.
    # 
    numbers = ['rei', 'ichi', 'ni', 'san', 'yon', 'go',
               'roku', 'nana', 'hachi', 'kyu']

    #
    # Modulus gives the remainder.
    # 12 divided by 10 is 1 with a remainder of 2.
    # It's a good way to get just the ones column.
    # Then we use regular division to get just the tens column
    #
    ones = number % 10
    tens = number / 10

    case tens
        # When we are doing 10 - 19
        when 1
            japanese = (0 == ones) ? 'ju' : 'ju ' + numbers[ones]

        # When we are doing 20 - 99
        when 2..9
            japanese = numbers[tens] + ' ju'

            if (ones > 0)
                japanese = [japanese, numbers[ones]].join(' ')
            end

        # Otherwise we are doing 0-9
        else
            japanese = numbers[ones]
    end

    return japanese
end

So there are a couple things I need to explain above. First is the case, when, else construct. The case statement tells Ruby that we are going to use the following expression (in this example the expression is a variable) with a bunch of comparisons. It’s a little nicer than doing a bunch of if/else statements. The first match is what gets run. Each case that we are checking is marked with the when statement. To translate it to English, it’s like saying “when tens is 1 do this”, “when tens is in the range 2..9 do that”, “otherwise do this”.

The next thing I have to explain is the (something) ? true : false construct. It’s a shorthand for an if/else statement. Essentially, we are saying that if the ones column is 0, just return ‘ju’ otherwise return ‘ju ’ plus the translation of the ones column. Have fun!

Using Many Objects at Once

Posted by Berin Loritsch Wed, 06 Aug 2008 11:53:00 GMT

Last article was meant to introduce you to the terminology that is common to object oriented languages. You should have a clear idea of what an Object is and what a Method is. Today, we are going to learn about how to use more than one object at a time. We’ll start with simple variables, which are simply names for objects you are using so you can get to them again. Then we’ll talk about some special objects called containers, whose sole purpose is to organize a group of objects for you.

A container is an object that holds a bunch of other objects

Variables

So there’s a little more terminology here. We can assign objects to individual variables fairly easily just by giving a name, using the equals sign, and the value. For example:

my_variable = 12345

As long as the first character of the variable name starts with a letter or an underscore “” character, the rest of the characters can be letters, numbers, and underscores. Almost all languages have this requirement, so that the computer doesn’t get confused between what is supposed to be a number and what is supposed to be a variable. Just a little helpful advice from someone with experience here, use variable names that make sense. It is better to type a few extra keys than wonder whether _cntr meant counter or center later on. It’s also better to use names that reflect the variable’s purpose rather than what it is made of.

array = ['cero', 'uno', 'dos', 'tres']
ones_column = ['cero', 'uno', 'dos', 'tres']

The variable named ‘array’ is kind of silly. It describes what kind of object is assigned to the variable rather than what we are using the variable for. The variable named ‘ones_column’ describes the purpose for the variable better. We are using an array of names to write out the ones column of a number.

Variables let us hold on to objects with a user friendly name so we can use them later

Arrays

Since we already introduced how to create an array above, let’s talk about how they are used. Arrays hold a bunch of related values together so that we can use them in interesting ways. Using the ‘ones_column’ example above, we can use any single digit number to get the name of that number.

Arrays are lists of information

puts ones_column[2]

# prints 'dos'

Remember in the last lesson, when we had a number do something using the times method? The number passed back to our code started at zero. The number inside the square brackets is an index number that starts at zero. So the first element in the array is always 0, not 1. That’s why we started the array with ‘cero’ (Spanish for zero) instead of ‘uno’ (Spanish for one).

An Array is a Collection, so like all collections it has an each method. The each method works just like the times method on the number objects. The method will pass back the elements (the objects) of the array one at a time in order. So, if we wanted to count in Spanish, we would use our ones_column array like this:

ones_column.each do |number|
  puts number
end

Hash

A Hash allows you to map one object as a key and another object as the value. Other languages will call the Hash a Map or a Dictionary, essentially letting you look up one object (a definition) using another object (the word to look up). Think of the word key in the terms of a map key. A symbol represents a concept, so to speak.

Hash lets you associate key objects with value objects

In Ruby, Hashes are created using the curly braces, and the key/value pairs are marked with the phrase: key => value . They can be quite handy when you have a lot of information to pass from one place to the next. One variable would take all the name/value pairs. If it helps, think of it as a collection of variables. It is most common to see string names be the key, but in Ruby we also have something called a symbol. Strings are surrounded by quotes, and they can change. Symbols have a colon in front and they never change.

my_map = {'string' => 'surrounded by quotes',
          :symbol => 'starts with colon',
          :string => 'not the same as a string'}

puts my_map['string'] # shows 'surrounded by quotes'
puts my_map[:symbol]  # shows 'starts with colon'
puts my_map[:string]  # shows 'not the same as a string'
puts my_map[:string.to_s] # shows 'surrounded by quotes'

In the above code, we set up a map of keys to string values. Just so you know, the objects don’t have to be the same type. In fact you’ll see that we used one string and two symbols for keys. You’ll also see that the Hash object treats them differently. The last lookup call might cause a little confusion, so look at the method being called on the symbol. The to_s method is on every Ruby object, and it is a convenient way to get a string out of the object. For a symbol, the to_s returns the name of the symbol (everything except for the colon). Because that happens to be the same name as a string key that is already in the map, it returns the value that belongs to the string.

This brings up a very important point, particularly for newbies. Save yourself a lot of headaches, and only use keys of the same type until you know exactly what you are doing. If you ever use many types of objects for different keys make sure you document your code with your comments. You don’t want to run the chance of spending hours tracking down a bug only to find it is the same thing I showed here. Talk about your ‘Doh!’ moments.

Strings

Ok, the Array and Map are good enough to get you going—there are more collection types and more things you can do with these collections, but strings are pretty important in programming. The string is your best tool for communicating with the user. On web forms, your values are all strings, and when you add content onto a page, they are strings. There are three ways of working with strings in Ruby, depending on how much power you need. We will introduce them from the simplest to the most complex.

Strings hold text

simple_string = 'single quotes and no processing'

The above string is rather simple. The single quotes mean to take the text AS IS, no escaped characters, no single quotes, and no formatting. You’d be surprised by how much you can use this simple declaration. If we ever needed to stick two strings together, we can use the plus sign (’+’).

hello = 'Hello'
world = 'World'

puts hello + ' ' + world

#shows 'Hello World'

Things can get messy when you have to show information your program has back to the user. The ’+’ concatenation only works for strings, so each object that is not a string needs to call the to_s method to be concatenated. Oh, and then you still have the problem of formatting the text to be pretty. There is a more powerful way to declare and use strings, and that is to use double quotes:

number = 4

puts "Number:\t#{number}" 

In the string we sent directly to the puts method, we see a bunch of stuff that might look confusing at first. The first funny looking characters would be the ”\t”. The backslash (’\’) is an escape character, so you can access more special characters with it. You can embed double quotes by adding a backslash in front, or in this case you can embed a tab character. Essentially, we told the string to embed some white space. The next set of funny looking characters would be ”#{number}”, but when you realize that the number inside the curly braces is the same name as the variable we defined before, it suddenly becomes a little less confusing. Basically anything between the ’#{’ and ‘}’ will be treated like regular ruby. You can even do math in there if you really wanted. It’s best to keep it simple and only use it to display the value of variables in your string.

That’s all well and good, but what if I have a lot of text, I only need to embed a little bit of Ruby variables, and I want to do all the spacing and carriage returns myself? There is a way to define a big string by providing your own “terminator”. The terminator is just so that Ruby can know when the string is done and it can go back to normal Ruby processing.

really_big = <<-END
This string will keep going and going
on and on until I use the terminator
to make it end.
END

puts really_big

You can embed variables just like before using the ’#{}’ construct, but there really isn’t a whole lot of need for escape characters and such. When you have a big message you want to give to the user, this is usually the best way to get it done. The important thing is that you choose the terminator so it will never be text in your block. The characters ‘<<-’ basically tell ruby to keep adding lines to the string until we reach X where X is the terminator. In my example, I chose the word END in all capital letters, but you could just as well use TERMINAR or BATTLE_FLAG or any other gibberish you want. The string will start on the following line and continue until it hits the terminator you set up. Just make sure it is clear what you are doing so that when you come back to the code later you aren’t thinking What in the world did I do?