Ruby Quirks

Ruby Quirks - peculiarity of behavior? I know this topic is debatable and remember 'one man's meat is another man's poison!

I plan to write down here (in no particular order), some of the little Ruby quirks that I've picked up and which, I now use comfortably.

1. Peter Cooper, the author of the book, 'Beginning Ruby' introduced me to Real-Time chat using an IRC client. On the #ruby channel at irc:// I heard of this quirk:

Check the output of the above program. In the code above,

sets the instance variable names by symbol to object, thereby frustrating the efforts of the class's author to attempt to provide proper encapsulation. The variable did not have to exist prior to this call.
Update: Hal Fulton in his excellent book 'The Ruby Way' has this to say about instance_variable_set:

It's true these methods are powerful and potentially dangerous. They should be used cautiously, not casually. But it's impossible to say whether encapsulation is violated without looking at how these tools are used. If they are used intentionally as part of a good design, then all is well. If they are used to violate the design, or to circumvent a bad design, then all is not well.

2. This one is not really a quirk but appears to be one, especially for people coming from a Java background. Last year, Shashank Date gave the PuneRuby members a presentation on 'Why Ruby Shines' and three points stood out - 'Expressions everywhere', 'Active Class Definitions' and 'Everything is an Object'.

Expressions everywhere - In Ruby, everything returns some value. Therefore a class definition is an expression and one can say something like:

The value of c is nil.

Active Class Definitions - Look at the following program:

When this class is read the first time, it executes puts and the output is - 'In class C'.

Everything is an Object - After being with Java since 1995, the concept that classes in Ruby are first-class objects, is hard to digest at first - each is an instance of class Class. When a new class is defined (typically using class Name ... end), an object of type Class is created and assigned to a constant (Name. in this case). Hal Fulton's suggests a mantra to be recited everyday - "Class is an object, and Object is a class."

3. If I want to swap two variables, I would normally use an additional temporary variable. In Ruby, this is not necessary:

will interchange the values of x and y.

4. Jaaron, a reader of the Learning Ruby Blog has this quirk for us. This one is well known and is the cause of much frustration.

If the name of a block parameter conflicts with the name of a local variable, the behavior is to assign the local variable to the argument. In this case, the local variable x gets assigned the value 1, then the value 2, then the value 3. The value 7 is lost.

If you refer to Programming Ruby Second Edition eBook (page 99) it says:

The while, until, and for loops are built into the language and do not introduce new scope; previously existing locals can be used in the loop, and any new locals created will be available afterward.

The blocks used by iterators (such as loop and each) are a little different. Normally, the local variables created in these blocks are not accessible outside the block.

However, if at the time the block executes a local variable already exists with the same name as that of a variable in the block, the existing local variable will be used in the block. Its value will therefore be available after the block finishes.

The whole issue with variable scope and blocks is one that generates considerable discussion in the Ruby community. The current scheme has definite problems (particularly when variables are unexpectedly aliased inside blocks), but at the same time no one has managed to come up with something that's both better and acceptable to the wider community. Matz is promising changes in Ruby 2.0.

5. Are instance variables inherited by a sub-class? David Black, the author of Ruby for Rails has this to say: Instance variables are per-object, not per-class, and they're not inherited. But if a method uses one, and that method is available to subclasses, then it will still use the variable -- but "the variable" in the sense of one per object. See the following program:

The output is:

6. Morgan Schweers, a reader of the Learning Ruby Blog has this quirk for us. Imagine for a moment, that you want to be able to set a variable, but if it's not set, you default to a known value. You'd rather do it on a single line.

One of my co-workers tried this:

but 'expand' is *defined* by being on the left hand side, BEFORE the RHS is evaluated, so defined? returns true, but because expand hasn't got a value yet, it returns nil.

I tried:

and it doesn't help either, which really shocked me. I always believed that the postfix-conditional was evaluated before even beginning to evaluate the operation, but I was distinctly disabused of this notion by testing.

Note that 'defined?' operator returns nil if its argument (which can be an arbitrary expression) is not defined; otherwise it returns a description of that argument.

I don't understand the reason for the behavior, and I think it's a bug, but I'd love to know a good language reason for it.

Kip, a reader writes in with this answer: Here is a work-around using the defined? method:

However, there is probably a much better way to accomplish this:

And Ruby even has a shortcut for that:

Anyway, just thought I'd share that (even though my guess is that you already knew this).

I am sure that you would have noticed many other Ruby quirks. I'd definitely like to hear and add them here.