In the eyes of ruby, 0 is true

Unlike many other languages, 0 isn’t qualified as false in an expression. For example :

To Ruby, only 2 things are false : false and nil. I should rather say : An instance of FalseClass and an instance of NilClass. Everything else is true. 0 is a Fixnum instance and therefore is considered to be true.

How ruby can return false when you write if(3>5) then? The answer is quite simple : It is false because 3>5 (or should I say 3.>(5)) returns an instance of FalseClass.

I thought it was something important to note as this unusual definition of truth can cause some headaches to the unwary…

3 steps to understand how classes and objects work in ruby

I made a simple list describing the 3 main things to consider when trying to understand how objects work in ruby. Feel free to add to this list as much as you want. Your comments are welcome and very appreciated.

1) The starting point is the object, not the class

To understand how objects and classes behave in ruby, we have to stop thinking in terms of classes and start thinking in terms of objects. Why? Because in ruby, a class is also an object. Every classes you are defining are instances of a class named Class. Each of these instances contains everything related to the structure of the object. Only one instance for each class definition is needed in a typical ruby / rails application. I mean, there would be no need to have both String.new() and String2.new(). Just one factory to create String instances is enough. However, if for some strange reason you would like to clone the definition of a class in another instance, you could still do it.

2) An object structure is not frozen and can be altered at any time

When you’re done defining your class and you put the end keyword, don’t think that this object (remember, a class is an object) is “safe” from future modifications, it isn’t. Everyone can modify your class structure. I know that dynamic languages are not for everyone (I imagine Java and C++ programmers shaking their heads in desperation right now…), but I personally find the freedom that they offer to be truly amazing.

#UPDATE 03/30/2007
Even if the above code really changed NoOneIsSafe structure, I realized that it also changed the structure of every single instances! Whatever you write some_obj.methods, String.methods, MyCustomClass.methods, you will see the im_hacking_this_object! method everytime. It’s definitely NOT something a sane person would want to do.

You could also add a method to a single instance of an object, like this :

3) Things that don’t look like objects often are

When trying to understand how objects work in ruby, you have to put the following sentence in the back of your head at all time : “Objects are everywhere… even if I can’t always see them“. A trivial statement like result = 5 + 3 must be understood the following way :

  • The “+” method of the Fixnum instance named “5″ is called
  • The Fixnum instance named “3″ is passed as a parameter to the “+” method.
  • The result of the call is a FixNum instance and is assigned to an object called “result”, which in turn becomes a FixNum instance

I talk about those hidden OO mechanisms in the following articles :
Oh Ruby, who are you trying to fool?
A trap to avoid with Ruby assignments

#UPDATE 03/31/2007
Gary Wright pointed out that you can only have one instance for a given Fixnum. For example, if you write :
a=1
b=1
c=1

1, a, b and c will all point to the same space in memory (Actually, these are not 4 different references to the same object. they are the same object). When you write 5 + 3, 5 already is a FixNum instance. The name of this instance is 5. Thanks to Gary for clearing this out.

An introduction to symbols

Symbols in Ruby are used everywhere and for good reasons. There are two main reasons of using them instead of strings (however they are absolutely not a replacement to strings, more on that later).

1. Semantics

When you write :dog, it is clear that you are refering to something. On the opposite, when you write “dog”, it only looks like the letters d, o and g. If you remove the double quotes, dog magically gets a meaning.

2. Efficiency

When ruby sees a symbol for the first time, it creates a space in memory for it. Every other use of the same symbol will refer to that space instead of being allocated a new one. Same thing, same place.

This is all fine and dandy, but what are symbols exactly?

A symbol is an instance of class Symbol

In this regard it isn’t different than any other ruby object. The way it differs is in how you use the object. A Symbol instance is used differently than an instance of an other class. First, you cannot create a Symbol instance that way :

To create a new Symbol instance, you simply have to use it like if it already existed. When ruby parses your code and finds a symbol for the first time, it creates an instance for it. The next time it will find the same object name (the name of the symbol) in your code, it will use the same space in memory (like any other object!).

So, to summarize : A symbol is simply an object with a special naming convention. The convention is that you must precede your symbol name with a colon “:” so ruby can understand that you want an instance of the Symbol class. Since Symbol.new() doesn’t work, there had to be some way to create an instance of this class… that’s exactly the purpose of the “:” character.

We don’t care about what’s contained inside a Symbol instance, we just care about it’s name

While there are several instance methods you can call in a Symbol object, most of the time you are only interested by it’s name. The purpose of a symbol is to centralize a meaning. You want to create names that will have a meaning for you and other programmers who may have to deal with your code later. You can think of symbols as an application wide registry table with 2 columns. The first column being the symbol object id (ex : 243938) and the second column being an associated name (ex : dog). Since we are humans and words have more meaning than numbers, we use the 2nd column to refer to a symbol.

Assignments

If you access a symbol directly, that is with the :symbol_name notation,you can’t assign to it. It wouldn’t make a lot of sense anyway. It’s like if you were saying that the left object was a symbol and, at the same time, that it was a String. However, if you assign a symbol to an object, future assignments to this object are allowed.

Comparing symbols to strings

If you write :dog == “dog”, ruby returns false. It is because you are comparing a string with a Symbol instance. It just cannot be the same. If for some reason you would like to check if some string is equal to the name of a symbol, you would have to write :dog.to_s == “dog”. Most of the time however, you will compare a Symbol instance with another Symbol instance.

Symbols are not better strings

Strings are all about content, symbols are all about meaning. When you write “dog”, the three letters are the only things that matter. If you decide to use the String form of a “dog”, it should be because you want to display the 3 letters on the screen or manipulate them in some way (capitalize, chomp!, reverse etc). When you write :dog, it is what a dog represents to your application that matters, not the individual letters. We only use words to define a symbol because we cannot use mental images (ruby is great, but that would be asking a bit too much…).

Symbols in hashes

You are probably comfortable using symbols with hashes already. animals[:dog] = “charlie” is something you see really often in ruby programs. As you might know, what the statement animals[:dog] = “charlie” really means to ruby is animals.[]=(:dog,”charlie”). The first parameter is a Symbol instance and the second parameter is the new value you want to store in the hash at the position associated with :dog. Every items in a hash are represented by a key and a value. In this specific case, the key is a Symbol instance. The []= method checks if there exists an item in the collection with the key part equals to the Symbol instance :dog. If it is the case, the 2nd parameter “charlie” is assigned to the value part of that same item.