I took a couple days’ break from the Ruby train. I had some other things I wanted to do, and darn it, I did them! I also needed some brain-recuperation time. Oh yeah, and I was finishing up the last episode (or 10…) of Nura: Rise of the Yokai Clan.

But now I’m back!

Day 4 of Ruby entails some tasty symbols, regular expressions, and methods.

Symbols

While I knew this going in, I’m finding more and more that Koans are a great tool for teaching how to use stuff in a language. What they are not great at, however, is explaining precisely what the “stuff” is.

Symbols are a great example of this gap. They’re scattered sneakily throughout the preceding examples, and seem easy enough to use. However, defining what a “symbol” is by virtue of the Koan itself leaves a bit to be desired.

So I did some reading. I eventually came across a nice article entitled “The Ruby_Newbie Guide to Symbols” by Steve Litt. In this article, Steve makes a helpful, birds-eye exploration of symbols in Ruby, sticking to broad categories and avoiding getting lost in the weeds of over-definition.

I’ll let you read Steve’s article for the full scoop, but my reading of symbols is that they are “things” comprised of an integer identifier and a string; are immutable (can’t be changed at runtime); are the same “thing”, regardless of how many times they are used (see below).

Clear as mud? Sure. However, an easy way (for me, at least) to think of symbols is to think of them in the context of a hash. Consider this example:

# create an array of hashes using strings for keys
names = []
names[0] = {"name" => "Joel"}
names[1] = {"name" => "Jason"}

In this example, we’re using strings for keys. However, when we do this, each instance of “name” becomes a separate object. We can see this by looking at the object id of each key:

names[0].keys[0].object_id // => something like 2167457900
names[1].keys[0].object_id // => something like 2167433500

As you can see, each key is its own object. No big deal in our example, but over thousands of keys, this would add up to some possibly significant memory usage.

Now, let’s do the same thing, but this time with symbols:

# create an array of hashes using symbols for keys
names = []
names[0] = {:name => "Joel"}
names[1] = {:name => "Jason"}

If we look at the object ids of the keys now, we’ll see something very interesting:

names[0].keys[0].object_id // => something like 435228
names[1].keys[0].object_id // => something like 435228

The object ids of the two keys are the same because…well…it’s the same symbol. Instead of a new object being created for each key, one symbol is shared between the two, as well as any other keys using the same symbol that we might create. As you can imagine, over thousands of iterations, this could add up to a decent performance win. Kind of cool.

Regular Expressions

I have a horrible aversion to regular expressions. I’m not very good at them, and frankly this Koan did not help that sentiment. I mostly muddled my way through this Koan, and I’ve decided that regular expressions are something that I need to dedicate some significant time to later this year.

Believe me, I’m not (just) trying to be lazy here. I honestly am not good at regular expressions AT ALL, so I don’t feel that I can speak even partially intelligently about any sort of evaluation of this Koan.

So, moving on… :)

Methods

The methods Koan was pretty tame–nothing terribly out-of-the-ordinary from what you’d expect to find in a discussion of using “methods” within language A, B, or C. There were a few interesting tidbits, through.

Look Ma, No Parentheses!

First, you can call methods with arguments without parentheses. So the following…

### define method
def my_method(a,b)
    a+b
end
### call method
result = mymethod 4,5  // => 9

This is disconcerting to me, a person who likes things “bracketized.” However, it’s there, so if you REALLY need to save those 2 keystrokes and don’t care about driving the OCD amongst us crazy, go for it.

Default Arguments

Another cool thing is that you can easily define default values for arguments directly in the method definition:

### define method
def my_method2(a,b=3)
    a+b
end
### call method
result = my_method(4) // -> 7

Explicit or Not Explicit Returns

Last, and perhaps in keeping with the possible frustrations inherent in #1, is that methods will potentially return values, whether or not you explicitly define a “return”. For example, the following will return the same value:

### define method
def my_method3(a,b=3)
    return a+b
end

### define method
def my_method4(a,b=3)
    a+b
end

There’s a part of me that hates that (I kind of like the self-documenting nature of brackets, specifying returns, etc.). However, I’m trying to keep an open mind to the patterns that are used in Ruby…hopefully it will make me better precisely by making me uncomfortable!

Wrapping Up

Another great day of Ruby. I’m happy with my progress so far, and I’m looking forward to Day 5!