# Making Hash a first-class citizen

**URL:** <https://www.ruby-forum.com/t/making-hash-a-first-class-citizen/173461>\
**Category:** Ruby\
**Created:** [August 9, 2009, 9:21pm UTC](https://www.ruby-forum.com/t/making-hash-a-first-class-citizen/173461 "2009-08-09T21:21:58Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Erik\_Michaels-Ober](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/85e7bf/32.png) [@Erik\_Michaels-Ober](https://www.ruby-forum.com/u/Erik_Michaels-Ober)\
**Post date:** [August 9, 2009, 9:21pm UTC](https://www.ruby-forum.com/t/making-hash-a-first-class-citizen/173461/1 "2009-08-09T21:21:58Z")

</div>

I’ve noticed a couple inconsistencies in the way Ruby hashes are treated  
(compared to, say, arrays). While I’ve been able to monkey-patch  
solutions,  
I thought I would bring these inconsistencies to the attention of the  
group  
with they hope that they might be resolved in a future version of the  
language, which I love dearly.

For starters, there’s no to\_hash method on nil. This causes a problem  
when  
I want to call an instance method on an object that may or may not be  
nil  
(for example, a hash of parameters from an HTTP request).

A common way to avoid a NoMethodError is by casting an object to a  
particular type before calling a method on it. For example:

string\_or\_nil.to\_s.capitalize

This technique can be used for arrays, floats, integers, and strings.  
It  
would seem to follow that I could do the same for hashes:

hash\_or\_nil.to\_hash.rehash

but instead I must do something like this:

(hash\_or\_nil || nil).rehash

or patch NilClass like this:

class NilClass  
def to\_hash  
{}  
end  
end

which seems to me like it shouldn’t be necessary for a “primitive” type.

Second, I would argue that there should be + (plus), - (minus), and &  
(ampersand) methods on hashes, that function the same way they do for  
arrays  
(concatenation, difference, and intersection, respectively).

These few changes would go a long way toward making Hash a first-class  
citizen in Ruby.

---

<div class="post-metadata">

**Author:** ![Erik\_Michaels-Ober](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/85e7bf/32.png) [@Erik\_Michaels-Ober](https://www.ruby-forum.com/u/Erik_Michaels-Ober)\
**Post date:** [August 9, 2009, 9:57pm UTC](https://www.ruby-forum.com/t/making-hash-a-first-class-citizen/173461/2 "2009-08-09T21:57:05Z")

</div>

Erik Michaels-Ober wrote:

> Second, I would argue that there should be + (plus), - (minus), and &  
> (ampersand) methods on hashes, that function the same way they do for arrays  
> (concatenation, difference, and intersection, respectively).

Hash is a very flexible citizen, though. It plays many roles. So how  
does this come out:

{0=\>1, 1=\>0} - {1=\>1} = ?

{0=\>1, 1=\>0}

# if you look at a hash as a set of pairs

{0=\>0}

# if you look at this hash as another way of expressing

# the same indexed collection as the array [1,0], and use

# Array#-

{0=\>1}

# if you look at a hash as a set of keys, with the value, as

# a boolean, representing membership or non-membership in the set

{0=\>1, 1=\>-1}

# maybe, if you look at a hash as a mathematical function

And then there are “Bags”:

{1=\>6} - {1=\>1} == {1=\>5}

---

<div class="post-metadata">

**Author:** ![Erik\_Michaels-Ober](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/85e7bf/32.png) [@Erik\_Michaels-Ober](https://www.ruby-forum.com/u/Erik_Michaels-Ober)\
**Post date:** [August 9, 2009, 10:50pm UTC](https://www.ruby-forum.com/t/making-hash-a-first-class-citizen/173461/3 "2009-08-09T22:50:21Z")

</div>

> {0=\>1, 1=\>0} - {1=\>1} = ?
> 
> {0=\>1, 1=\>0}
> 
> # if you look at a hash as a set of pairs

I do look at Hash as a set of pairs and I would consider the other uses  
you  
cite to be “non-standard”. The first line of RDoc for the class states:  
“A  
Hash is a collection of key-value pairs.”

I would argue it’s better for +, -, and & to be defined for the standard  
use  
case than to remain undefined in the language. Those using Hash in a  
non-standard way can simply avoid these methods.

You could just as well argue that someone might want [6] - [1] to return  
[5], but that wouldn’t make sense given that “Arrays are ordered,  
integer-indexed collections of any object.”

Any objections to nil.to\_hash?

Note: in the example I meant to type (hash\_or\_nil || {}).rehash instead  
of  
(hash\_or\_nil || nil).rehash

---

<div class="post-metadata">

**Author:** ![Erik\_Michaels-Ober](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/85e7bf/32.png) [@Erik\_Michaels-Ober](https://www.ruby-forum.com/u/Erik_Michaels-Ober)\
**Post date:** [August 10, 2009, 7:00am UTC](https://www.ruby-forum.com/t/making-hash-a-first-class-citizen/173461/4 "2009-08-10T07:00:15Z")

</div>

> Concatenation does not make sense with an unordered collection.

There are also the merge and delete methods. Should + be simply  
aliases for those? I personally would favour making those operators  
work on the set of keys.

> > Any objections to nil.to\_hash?

Nil is nil. Maybe there is a reason why the variable/value in question  
is nil and not {}? If so, you probably shouldn’t ignore that  
distinction?

---

<div class="post-metadata">

**Author:** ![Erik\_Michaels-Ober](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/85e7bf/32.png) [@Erik\_Michaels-Ober](https://www.ruby-forum.com/u/Erik_Michaels-Ober)\
**Post date:** [August 9, 2009, 11:10pm UTC](https://www.ruby-forum.com/t/making-hash-a-first-class-citizen/173461/5 "2009-08-09T23:10:50Z")

</div>

On 09.08.2009 22:49, Erik Michaels-Ober wrote:

> > {0=\>1, 1=\>0}
> > 
> > # if you look at a hash as a set of pairs
> 
> I do look at Hash as a set of pairs and I would consider the other uses you  
> cite to be “non-standard”. The first line of RDoc for the class states: “A  
> Hash is a collection of key-value pairs.”

You omit a very important additional property: no key can occur twice in  
a Hash. Actually I would consider at least option one and three of  
Joel’s list as common usage of a Hash.

> I would argue it’s better for +, -, and & to be defined for the standard use  
> case than to remain undefined in the language. Those using Hash in a  
> non-standard way can simply avoid these methods.

The problem is that there is no standard use case. Removing based on  
the identical pair seems to me as valid as removing based on the key  
only as implementations for Hash#-.

Concatenation does not make sense with an unordered collection. See  
also various discussions why Hash does not (or rather did not) implement  
#hash and #eql? as many people expected.

> You could just as well argue that someone might want [6] - [1] to return  
> [5], but that wouldn’t make sense given that “Arrays are ordered,  
> integer-indexed collections of any object.”

Well, the implementation of Array#- does not fit there well, does it?  
Because it works like set substraction while Array#+ works as array  
concatenation - not very consistent either - but apparently useful.

> Any objections to nil.to\_hash?
> 
> Note: in the example I meant to type (hash\_or\_nil || {}).rehash instead of  
> (hash\_or\_nil || nil).rehash

What other classes do implement to\_hash? In 1.9.1:

irb(main):007:0\> ObjectSpace.each\_object(Module) {|cl| p cl if  
cl.instance\_methods.include? :to\_hash}  
Hash  
=\> 407  
irb(main):008:0\>

Btw, invoking x.to\_hash is not a cast. First, there are no casts in  
Ruby because variables do not have types and second, to\_hash is an  
ordinary method. Casts on the other hand are usually not implemented  
via ordinary methods. (In C++ for example casts are operators which can  
be overloaded.)

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![Erik\_Michaels-Ober](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/85e7bf/32.png) [@Erik\_Michaels-Ober](https://www.ruby-forum.com/u/Erik_Michaels-Ober)\
**Post date:** [August 10, 2009, 8:01pm UTC](https://www.ruby-forum.com/t/making-hash-a-first-class-citizen/173461/6 "2009-08-10T20:01:12Z")

</div>

Erik, when I’ve needed set-like behavior in ruby, I just used the Set  
class. 🙂 You should see if a set of hashes does what you need.

As far as having a .to\_h method for Nil, I think you’ve got a good idea  
there. Nil has to\_a, to\_c, to\_f, to\_i, to\_r, and to\_s; having a to\_h  
seems consistent and expected to me. I recommend you write a patch and  
submit it to the ruby developers. Even if C isn’t your language, you  
should be able to figure out something this simple by looking at the  
source for similar methods.
