What's the rules re whether a Hash can use either a Symbol or String to reference the value?


#1

Hi,
Getting confused with Hashes a bit. It seems sometimes I can use both a
Symbol or a String to get the value back, but other times the Symbol
doesn’t
work. Is there any rule re how to remember how Hash handles setting and
getting values uses Symbol / String?

e.g. hash_variable[:amount] versus hash_variable[“amount”]

e.g. hash_var = {:amount => 10}, versus hash_var = {“amount” => 10)


#2

On Mon, Jan 12, 2009 at 9:50 PM, Greg H.
removed_email_address@domain.invalid wrote:

Hi,
Getting confused with Hashes a bit. It seems sometimes I can use both a
Symbol or a String to get the value back, but other times the Symbol doesn’t
work. Is there any rule re how to remember how Hash handles setting and
getting values uses Symbol / String?

e.g. hash_variable[:amount] versus hash_variable[“amount”]

e.g. hash_var = {:amount => 10}, versus hash_var = {“amount” => 10)

In general, a hash uses eql? to know if a key matches the one you are
asking for.
So in general a Symbol and it’s String counterpart are not the same
key in a hash.
There are different implementations that allow using Strings / Symbols
to refer to the same key.
Search for HashWithIndifferentAccess or something like that. I think
Rails uses something similar, IIRC.
Maybe your confusing comes from the different behaviour when you are
using Rails vs non-Rails?

Jesus.


#3

Alle lunedì 12 gennaio 2009, Greg H. ha scritto:

Hi,
Getting confused with Hashes a bit. It seems sometimes I can use both a
Symbol or a String to get the value back, but other times the Symbol
doesn’t work. Is there any rule re how to remember how Hash handles
setting and getting values uses Symbol / String?

e.g. hash_variable[:amount] versus hash_variable[“amount”]

e.g. hash_var = {:amount => 10}, versus hash_var = {“amount” => 10)

By itself, a hash distinguish between strings and symbols, so if an
entry is
stored under a string key, you’ll only be able to retrieve it using a
string
key. If the entry has a symbol entry, then it can only be obtained using
a
symbol key:

h ={‘a’ => 1, :b => 2}
puts h[‘a’] # => 1
puts h[:a] # => nil
puts h[:b] # => 2
puts h[‘b’] # => nil

You can setup the hash so that it will work either with strings or
symbols.
For example:

hash = Hash.new do |h, k|
if k.is_a?(String) and h.has_key? k.to_sym then h[k] = h[k.to_sym]
elsif k.is_a?(Symbol) and h.has_key? k.to_s then h[k] = h[k.to_s]
else nil
end
end

hash[‘a’] = 1
hash[:b] = 2
puts hash[‘a’] # => 1
puts hash[:a] # => 1
puts hash[:b] # => 2
puts hash[‘b’] # => 2
puts hash[1] # => nil

See the documentation for Hash.new to see how passing it a block works.

I hope this helps

Stefano


#4

Greg H. schrieb:

first:
every time you call hash_var[“amount”] a new string is created.
But if you call with :amount, :amount will always be the same object.

next:
the default Hash class does not mix String- and Symbol-Keys.
so
hash_var[:amount] = 10
hash_var[“amount”] = 11
hash_var[:amount] != hash_var[“amount”] # => true

but for example ActiveSupport (used in Rails) defines a class
HashWithIndifferentAccess.
there all Symbol-keys gets converted to a String, so that either :amount
or “amount” point to the same entry.

So if you want to know how to handle it, ask the variable for its class
(if someone uses monkey-patching you will lose =P)


#5

Hi –

On Tue, 13 Jan 2009, Greg H. wrote:

thanks guys - interesting question for the Rails guys is whether you have to
explicitly ask for a HashWithIndifference, i.e. just wondering whether it’s
possible in Rails to ask for a Hash but really get a monkey patched
HashWithIndiffrence back without it being obvious…

HashWithIndifferentAccess is just a subclass of Hash. I don’t think it
can be described as monkey patched, though I’m never sure what that
term means. Some methods return instances of it; some return instances
of Hash.

David


David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Coming in 2009: The Well-Grounded Rubyist (http://manning.com/black2)

http://www.wishsight.com => Independent, social wishlist management!


#6

Greg H. wrote:

thanks guys - interesting question for the Rails guys is whether you
have to
explicitly ask for a HashWithIndifference, i.e. just wondering whether
it’s
possible in Rails to ask for a Hash but really get a monkey patched
HashWithIndiffrence back without it being obvious…

There is no guarantees of getting any “type” back from ANY method in
ruby… with rails, you can just convert it to an one if you aren’t
sure…

my_hash = HashWithIndifferentAccess.new(my_hash)

By the way, there is no monkey patching here… HashWithIndifferentAccess
is it’s own class. To be considered monkey patching, the Hash class
itself would be modified to be used in an indifferent fashion…

ilan


#7

thanks guys - interesting question for the Rails guys is whether you
have to
explicitly ask for a HashWithIndifference, i.e. just wondering whether
it’s
possible in Rails to ask for a Hash but really get a monkey patched
HashWithIndiffrence back without it being obvious…


#8

agreed - slip on my part to use the term - what I meant to refer to was
“Some methods return instances of it; some return instances of Hash” -
as
Ilan pointed out, confirming that Rails can do this to you…


#9

On 12.01.2009 22:02, Stefano C. wrote:

You can setup the hash so that it will work either with strings or symbols.
For example:

hash = Hash.new do |h, k|
if k.is_a?(String) and h.has_key? k.to_sym then h[k] = h[k.to_sym]
elsif k.is_a?(Symbol) and h.has_key? k.to_s then h[k] = h[k.to_s]
else nil
end
end

IMHO there is a downside to assign to the hash in the block because that
changes the Hash. This would not work with a frozen Hash for example.

I’d probably rather adjust keys on insertion and retrieval, e.g. always
change them to Symbols.

Kind regards

robert