On Sun, Aug 04, 2002 at 03:05:49AM +0900, Tom Sawyer wrote:
> i've been thinking about posting this as an RCR.
> 
> i would really like to see hash pairs (associations) become real
> objects. i think it would be a very powerful and useful construct. there
> are number of things one could then do. The simpliest obviosuly being:
> 
>   x = 'a'=>1
>   y = 'b'=>2
> 
>   hash = { x, y }

A pair is a real object; it's called an array (with length=2).
Extensions often need to create such an object using rb_assoc_new (from
array.c):

  VALUE
  rb_assoc_new(car, cdr)
      VALUE car, cdr;
  {
      VALUE ary;

      ary = rb_ary_new2(2);
      RARRAY(ary)->ptr[0] = car;
      RARRAY(ary)->ptr[1] = cdr;
      RARRAY(ary)->len = 2;

      return ary;
  }

> ordered hashes also become a snap, implemented as arrays of these
> associations:
> 
>   ordhash = [ x, y ]

In Ruby, this is done with an array of arrays:

   x = ['a', 1]
   y = ['b', 2]
   ordhash = [ x, y ]
   p ordhash.assoc('a')[1] #=> 1

> or, without the above x and y assignments, just
> 
>   ordhash = [ 'a'=>1 , 'b'=>2 ]
> this association class (Assoc?) would of course mixin the comparable
> module.

This might be useful.  But how would this comparison be done?  Would it
compare keys or values?  Or a combination?

> the Assoc class becomes very useful when you start to build more comlex
> structures (what i would like to use it for):
> 
>   c = [ 'a'=>1, 's' ]
> 
> this is a very simple example, but without the Assoc you'd have to write
> this as:
>   
>   c = { 'a'=>1, 's'=>nil }

I see no reason why Ruby should assume that if 's' has a key but no
value associated with it that it should get nil.  It would be MUCH more
useful to me to have the default be true, instead.  I doubt there can be
a default that will please everyone.

If you create a hash, then elements with no keys get nil by default.  So
what you have written is not too different from:

  c = { 'a'=> 1 }
  p c['s'] #=> nil

except that iterating over the above structure produces a different
result.

> adding a useless nil, or
> 
>   c = [ ['a', 1], 's' ]
> 
> whereby you have to use indexes on the association.

Here's an option:

  c = [ ['a', 1], 's' ]
  d = c.map { |x| Array === x ? x : [ x, nil ] }
  e = Hash[*d]

You can put this into a function somewhere if you want to avoid writing
it over and over.

> i'm sure there are other uses as well, and i think it may be possible
> that such an Assoc class combined with arrays could ultimatly displace
> regular hashes altogether.

Hashes have O(1) lookups, but are not ordered.  An array of assocs has
O(n) lookups, but are ordered.  Trees make a good compromise (more
complex, but ordered with O(log(n)) lookups), which would probably make
a better choice.

Paul