Strings or symbols?

When working with a record that has various fields represented using a
hash, do you prefer strings or symbols? Why?

With strings, it’s like this:

person = {
    :name => "John Doe",
    :age => 20
}

With symbols, it’s like this:

person = {
    'name' => "John Doe",
    'age' => 20
}

Symbols are one character shorter to type (:name v.s. ‘name’). But,
then I have to convert between symbols and strings sometimes using
String#intern or Symbol#id2name. I do a lot of CGI programming; if a
script like this is called:

add_person.rhtml?name=John%20Doe;age=20

then the “name” and “age” are given to me as strings, so I have to
call String#intern in order to convert them into symbols first.

When working with a record that has various fields represented using a
hash, do you prefer strings or symbols? Why?

With strings, it’s like this:

person = {
    :name => "John Doe",
    :age => 20
}

With symbols, it’s like this:

person = {
    'name' => "John Doe",
    'age' => 20
}

Your examples are the wrong way around!

Symbols are one character shorter to type (:name v.s. ‘name’). But,
then I have to convert between symbols and strings sometimes using
String#intern or Symbol#id2name. I do a lot of CGI programming; if a
script like this is called:

add_person.rhtml?name=John%20Doe;age=20

then the “name” and “age” are given to me as strings, so I have to
call String#intern in order to convert them into symbols first.

Given all this, I would use Strings if I were you. For plain indices that
don’t really need to be interpreted outside the hash, I use symbols. I think
symbols are more efficient, too (but probably not if you’re converting them to
strings all the time).

Gavin

···

From: “Philip Mak” pmak@aaanime.net

Philip Mak wrote:

When working with a record that has various fields represented using a
hash, do you prefer strings or symbols? Why?

person = {
    :name => "John Doe",
    :age => 20
}

I would probably use symbols, since it is the same few values used many
times.

But wouldn’t write code like the above. I would create a class “Person”
instead. Hashes with a fixed set of keys are almost screaming for you to
create a new class.

/Anders

···

A n d e r s B e n g t s s o n | ndrsbngtssn@yahoo.se
Stockholm, Sweden |


Gratis e-mail resten av livet på www.yahoo.se/mail
Busenkelt!

Gavin Sinclair wrote:

Given all this, I would use Strings if I were you. For plain indices that
don’t really need to be interpreted outside the hash, I use symbols. I think
symbols are more efficient, too (but probably not if you’re converting them to
strings all the time).

Or converting strings to symbols, if I understood the OP correctly :slight_smile:

As I understand it, the potential gain in using symbols, is depending on
how the hash value is computed. Since a symbol is an internalized
string, it could potentially be quicker. I tried a quick and dirty
profiling test. Not surprising, using symbols are quicker than using
strings. Naturally stringifying a symbol or interning a string before
hash lookup is slower than either of the above. (Quite surprising to me,
they both appear to be approximately equal in time usage.)

So it is a matter of weighing how many times you guess you will be
looking up with symbols directly versus when you need to internalize a
string. If the script sets the variables from the CGI once (requiring an
intern to get symbol), but access it in the script elsewhere using
symbol a lot of times, symbols would be the way to go. (CGI
communication usually is slow as heck anyway, since you probably have a
user infront of a HTML form being the slowest link :slight_smile:

require 'profile'

N = 10000
H = { :abba => ‘:A’, ‘abba’ => ‘A’ }

def time_strings
N.times do |i| H[‘abba’] end
end
def time_string_interned
N.times do |i| H[‘abba’.intern] end
end
def time_symbols
N.times do |i| H[:abba] end
end
def time_symbols_stringified
N.times do |i| H[:abba.to_s] end
end

time_strings
time_symbols
time_string_interned
time_symbols_stringified

[kentda@v052a ruby]$ /usr/local/bin/ruby symbol.rb % cumulative self self total time seconds seconds calls ms/call ms/call name 63.43 7.13 7.13 4 1782.50 2810.00 Integer#times 14.41 8.75 1.62 40000 0.04 0.04 Hash#[] 9.07 9.77 1.02 30004 0.03 0.03 String#allocate 8.99 10.78 1.01 10000 0.10 0.13 Symbol#to_s 4.09 11.24 0.46 10000 0.05 0.05 String#intern 0.00 11.24 0.00 1 0.00 11240.00 #toplevel 0.00 11.24 0.00 1 0.00 1390.00 Object#time_symbols 0.00 11.24 0.00 1 0.00 3680.00 Object#time_symbols_stringified 0.00 11.24 0.00 4 0.00 0.00 Module#method_added 0.00 11.24 0.00 1 0.00 2520.00 Object#time_strings 0.00 11.24 0.00 1 0.00 3650.00 Object#time_string_interned [kentda@v052a ruby]$ /usr/local/bin/ruby --version ruby 1.7.2 (2002-07-13) [i686-linux]
···


([ Kent Dahl ]/)_ ~ [ http://www.stud.ntnu.no/~kentda/ ]/~
))_student
/(( _d L b_/ NTNU - graduate engineering - 5. year )
( __õ|õ// ) )Industrial economics and technological management(
_
/ö____/ (_engineering.discipline=Computer::Technology)

person = {
    :name => "John Doe",
    :age => 20
}

But wouldn’t write code like the above. I would create a class
“Person” instead. Hashes with a fixed set of keys are almost
screaming for you to create a new class.

I’ve thought of doing that, but I found certain properties of the hash
to be convenient. For example, Hash#keys will tell me the name of all
the fields inside the hash. Then, if I have a “person” object as
defined above, storing it into SQL is pretty simple:

(code not tested, but should be more or less right)

def insert(table, hash)
Db.do “INSERT INTO #{table} SET #{
#{hash}.to_a.collect {
>key, value| “#{key} = #{Mysql.quote(value)}”
}.join(”, “)
}”
end

insert(‘person’, person)

When I do it with a class, there doesn’t seem to be a way to get a
list of all the attributes in the class. (Or is there? If there was a
good way, I think it would be better for me to use classes since then
I get all the other nice features of classes.)

Philip Mak wrote:

person = {
    :name => "John Doe",
    :age => 20
}

But wouldn’t write code like the above. I would create a class
“Person” instead. Hashes with a fixed set of keys are almost
screaming for you to create a new class.

I’ve thought of doing that, but I found certain properties of the hash
to be convenient. For example, Hash#keys will tell me the name of all
the fields inside the hash. Then, if I have a “person” object as
defined above, storing it into SQL is pretty simple:

(code not tested, but should be more or less right)

def insert(table, hash)
Db.do “INSERT INTO #{table} SET #{
#{hash}.to_a.collect {
>key, value| “#{key} = #{Mysql.quote(value)}”
}.join(”, “)
}”
end

insert(‘person’, person)

You can get the names of all instance variables of an object with
obj.instance_variables, so you could write something similar to the
above.
If you have everything in a Person class you can also let that class
know about the table structure the instances are stored in, so the
objects can store themselves even.

/Anders

···

A n d e r s B e n g t s s o n | ndrsbngtssn@yahoo.se
Stockholm, Sweden |


Följ VM på nära håll på Yahoo!s officielle VM-sajt www.yahoo.se/vm2002
Håll dig ajour med nyheter och resultat, med vinnare och förlorare…

True. Two other possibilities:

  1. Give your class a to_hash method (maybe
    from_hash also)
  2. Use a Struct

Hal

···

----- Original Message -----
From: “Anders Bengtsson” ndrsbngtssn@yahoo.se
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Thursday, October 17, 2002 1:14 PM
Subject: Re: Hashes v.s. Classes (was Re: Strings or symbols?)

You can get the names of all instance variables of an object with
obj.instance_variables, so you could write something similar to the
above.
If you have everything in a Person class you can also let that class
know about the table structure the instances are stored in, so the
objects can store themselves even.