Thursday, November 29, 2007

Difference between Strings and Symbols in Ruby

Symbols have two nice properties compared to strings which can save you memory and CPU time:

Memory

For every unique string value, there is a unique symbol object. Three strings with the same value can use up to three times the memory of three symbols with the same value. This is because those three symbols are actually the same object.

p "blah".object_id #=> -605600196
p "blah".object_id #=> -605618816
p "blah".object_id #=> -605637168
 
p :blah.object_id #=> 4071694
p :blah.object_id #=> 4071694
p :blah.object_id #=> 4071694
 
p "blah".to_sym.object_id #=> 4071694
p "blah".to_sym.object_id #=> 4071694
p "blah".to_sym.object_id #=> 4071694
 
I think now you can understand

Symbol objects are created on-demand behind the scenes for new unique string values. Once a symbol exists for a particular string value, it will continue to be used for that value rather than creating more symbols for it.

Of course, this has a disadvantage: Ruby keeps symbols around forever (well, until the end of your program anyway), in case they are needed again.

That’s fine if the number of unique symbols is relatively small and you expect to keep reusing them. However, if you have an unlimited number of string values, and/or you only use each one briefly (for example, lines arriving on an input stream), symbols are not the tool for you. You’ll just use up all your memory.

CPU Time

Testing two symbol values for equality (or non-equality) is faster than testing two string values for equality, because Ruby only needs to do a single test. Checking two strings for equality is more complicated; every individual character in the string has to be checked until a difference is found.

As noted above, each unique string value has an associated symbol. This means that checking whether two symbols have the same string value or not is as simple as checking whether they are the same object or not.

One comparison:

:Worcestershire == :Worcestershire

Easy peasy. They’re the same object, so they’re equal.

Sixteen comparisons:

"Worcestershire" == "Worcestershire"

With strings, Ruby has to dig into the objects to check their contents. Since in this case they’re different string objects with the same length, it’s got to check all fourteen characters in each string to make sure that they really are equal.

However, what symbols don’t give you is lexical comparison. You can do "foo" > "bar", but not :foo > :bar. They’re digested. Their original string values are a memory which can be resurrected only via Symbol#to_s.

The Right Tool for the Job

If you have a modest number of unique string values that you want to use over and over, and will mostly be using them as-is (i.e. not concatenating them, uppercasing them, etc….), then symbols are the right tool for you.

Method names (such as those given to Module#attr_reader, or Object#send) are a good example of this; in fact, Ruby uses symbols internally to remember method, variable, and constant names.

Otherwise, stick with strings. Strings are not that much slower than symbols, and many times the extra limitations of symbols aren’t worth it.

Wednesday, November 14, 2007

Rails 2.0 - Preview Release

Its time to feel the Real Power of Rails.
The Rails 2.0 preview version is just released.

I've listed down some of the important updates of Rails 2.0 here

Action Pack - Multiview

In Rails 2.0, the format of the template is separated from its rendering engine. So show.rhtml now becomes show.html.erb, which is the template that’ll be rendered by default for a show action that has declared format.html in its respond_to. And you can now have something like show.csv.erb, which targets text/csv, but also uses the default ERB renderer.

So the new format for templates is action.format.renderer. A few examples:

  • show.erb: same show template for all formats
  • index.atom.builder: uses the Builder format, previously known as rxml, to render an index action for the application/atom+xml mime type

Action Pack: Record identification

Piggy-backing off the new drive for resources are a number of simplifications for controller and view methods that deal with URLs. We’ve added a number of conventions for turning model classes into resource routes on the fly. Examples:


# person is a Person object, which by convention will
# be mapped to person_url for lookup
redirect_to(person)
link_to(person.name, person)
form_for(person)

Action Pack: HTTP Loving

New module is added in Rails 2.0 to work with HTTP Basic Authentication, which turns out to be a great way to do API authentication over SSL. It’s terribly simple to use. Here’s an example (there are more in ActionController::HttpAuthentication):


class PostsController < password = "dhh" except =""> [ :index ]

def index
render :text => "Everyone can see me!"
end

def edit
render :text => "I'm only accessible if you know the password"
end

private
def authenticate
authenticate_or_request_with_http_basic do |user_name, password|
user_name == USER_NAME && password == PASSWORD
end
end
end

Active Record: Sexy migrations

There’s a new alternative format for declaring migrations in a slightly more efficient format. Before you’d write:

create_table :people do |t|
t.column, "account_id", :integer
t.column, "first_name", :string, :null => false
t.column, "last_name", :string, :null => false
t.column, "description", :text
t.column, "created_at", :datetime
t.column, "updated_at", :datetime
end

Now you can write:

create_table :people do |t|
t.integer :account_id
t.string :first_name, :last_name, :null => false
t.text :description
t.timestamps
end

And hundreds upon hundreds of other improvements

We’ve got literally hundreds of bug fixes, tweaks, and feature enhancements crammed into Rails 2.0. All this coming off the work of tons of eager contributors working tirelessly to improve the framework in small, but important ways.

So how do I upgrade?

If you want to move your application to Rails 2.0, you should first move it to Rails 1.2.3. That’ll include deprecation warnings for most everything we yanked out in 2.0. So if your application runs fine on 1.2.3 with no deprecation warnings, there’s a good chance that it’ll run straight up on 2.0. Of course, if you’re using, say, pagination, you’ll need to install the classic_pagination plugin. If you’re using Oracle, you’ll need to install the activerecord-oracle-adapter gem. And so on and so forth for all the extractions.

To install the preview release through gems, do:

gem install rails --source http://gems.rubyonrails.org

To try it from an SVN tag, use:

rake rails:freeze:edge TAG=rel_2-0-0_PR


Thanks to
David Heinemeier Hansson and the core team of committers and hundreds of open-source contributors