Forum: Ruby-core [Feature #3131] add Kernel#Hash() method like Kernel#Array()

Posted by Suraj Kurapati (Guest)
on 2010-04-12 01:34
(Received via mailing list)
Feature #3131: add Kernel#Hash() method like Kernel#Array()
http://redmine.ruby-lang.org/issues/show/3131

Author: Suraj Kurapati
Status: Open, Priority: Normal
Category: core, Target version: 1.9.x

Hello,

There is an imbalance of power in the Ruby core API (when it comes
to arrays and hashes) because it is easier to convert nil values
into empty arrays, thanks to Kernel#Array(), than it is to convert
nil values into empty hashes, due to lack of Kernel#Hash().

To correct this asymmetry and restore a balance of power, please
add a Kernel#Hash() method for converting nil, Array, and Hash
values into hashes:

    module Kernel
      def Hash(value)
        if value.respond_to? :to_hash
          value.to_hash
        elsif value.respond_to? :to_ary
          Hash[*value.to_ary]
        elsif value.nil?
          {}
        else
          raise ArgumentError, "invalid value for Hash: #{value}"
        end
      end
    end

For example, here is how I would use the above API:

    #-------------------------------------------------------------------------
    # CASE 1: to_hash
    #-------------------------------------------------------------------------

    real_hash = {:real => true}
    Hash(real_hash) # => {:real=>true}

    fake_hash = Object.new
    def fake_hash.to_hash
      {:fake => true}
    end
    Hash(fake_hash) # => {:fake=>true}

    #-------------------------------------------------------------------------
    # CASE 2: to_ary
    #-------------------------------------------------------------------------

    real_array = [:real, true]
    Hash(real_array) # => {:real=>true}

    fake_array = Object.new
    def fake_array.to_ary
      [:fake, true]
    end
    Hash(fake_array) # => {:fake=>true}

    #-------------------------------------------------------------------------
    # CASE 3: nil
    #-------------------------------------------------------------------------

    Hash(nil) # => {}

    #-------------------------------------------------------------------------
    # CASE 4: unsupported arguments
    #-------------------------------------------------------------------------

    >> Hash(true)
    ArgumentError: invalid value for Hash: true
            from (irb):74:in `Hash'
            from (irb):80
            from /usr/bin/irb:12:in `<main>'

    >> Hash(false)
    ArgumentError: invalid value for Hash: false
            from (irb):74:in `Hash'
            from (irb):81
            from /usr/bin/irb:12:in `<main>'

    >> Hash(123)
    ArgumentError: invalid value for Hash: 123
            from (irb):74:in `Hash'
            from (irb):82
            from /usr/bin/irb:12:in `<main>'

Thanks for your consideration.
Posted by Suraj Kurapati (Guest)
on 2010-04-12 01:38
(Received via mailing list)
Issue #3131 has been updated by Suraj Kurapati.


I forgot to show that case 2 supports empty arrays:

>> Hash([])
=> {}

Just like Kernel#Array() supports empty hashes:

>> Array({})
=> []

Thanks for your consideration.  And sorry for the noise.
----------------------------------------
http://redmine.ruby-lang.org/issues/show/3131
Posted by Yukihiro Matsumoto (Guest)
on 2010-04-13 01:11
(Received via mailing list)
Hi,

In message "Re: [ruby-core:29462] [Feature #3131] add Kernel#Hash() 
method like Kernel#Array()"
    on Mon, 12 Apr 2010 08:32:52 +0900, Suraj Kurapati 
<redmine@ruby-lang.org> writes:

|There is an imbalance of power in the Ruby core API (when it comes 
|to arrays and hashes) because it is easier to convert nil values 
|into empty arrays, thanks to Kernel#Array(), than it is to convert 
|nil values into empty hashes, due to lack of Kernel#Hash().

Having Hash() might be a good idea.  But since conversion from
arrays only meaningful for specific case (array of 2-element arrays),
I am not sure whether Hash() should support conversion from Array in
general or not.

              matz.
Posted by Suraj Kurapati (Guest)
on 2010-04-13 02:07
(Received via mailing list)
Issue #3131 has been updated by Suraj Kurapati.


Hi,

matz wrote:
> since conversion from arrays only meaningful for specific case
> (array of 2-element arrays), I am not sure whether Hash() should
> support conversion from Array in general or not.

Hash::[] does not support conversion from odd-length Array (because
it is uncertain what Ruby must do with the 2n+1'th element) and will
raise an error in such case.  So, in my view, Kernel#Hash() need not
support conversion from odd-length Array either.

If you wish to avoid even-length Array conversion in Kernel#Hash()
because odd-length Array conversion is not supported, then I request
that Kernel#Hash() must still support conversion from empty Array
because Kernel#Array() already supports conversion from empty Hash:

>> Array({})
=> []

In summary, I request that Kernel#Hash() supports conversion from:

* nil
* Hash
* empty Array

It would be nice if Kernel#Hash() also supports conversion from:

* even-length Array

Thanks for your consideration.
----------------------------------------
http://redmine.ruby-lang.org/issues/show/3131
Posted by Suraj Kurapati (Guest)
on 2010-04-13 02:19
(Received via mailing list)
Issue #3131 has been updated by Suraj Kurapati.


Hi,

Please allow me to clarify.

Suraj Kurapati wrote:
> Hash::[] does not support conversion from odd-length Array (because
> it is uncertain what Ruby must do with the 2n+1'th element) and will
> raise an error in such case.

I was referring to this particular behavior:

>> Hash[1,2,3,4,5,6]
=> {1=>2, 3=>4, 5=>6}

>> Hash[1,2,3,4,5,6,7]
ArgumentError: odd number of arguments for Hash
  from (irb):3:in `[]'
  from (irb):3
  from /usr/bin/irb:12:in `<main>'

I forgot that Hash::[] can convert Array of 2-element Array into Hash:

>> Hash[1,2,3,4,[5,6],[7]]            # non 2-element Array ignored
=> {1=>2, 3=>4, [5, 6]=>[7]}

>> Hash[[1,2,3,4,[5,6],[7]]]          # implicit pair value is nil
=> {5=>6, 7=>nil}

>> Hash[[1,2,3,4,[5,6],[7,8],[7]]]    # previous pair is overwritten
=> {5=>6, 7=>nil}

Thanks for your consideration.
----------------------------------------
http://redmine.ruby-lang.org/issues/show/3131
Posted by Suraj Kurapati (Guest)
on 2010-04-20 06:36
(Received via mailing list)
Issue #3131 has been updated by Suraj Kurapati.


Hi Matz,

To avoid delaying this request forever due to unnecessary features,
I have narrowed the requirements for Kernel#Hash() to the following:

Hash() must convert (1) nil, (2) Hash, and (3) empty Array into Hash.

    module Kernel
      def Hash(value)
        if value.respond_to? :to_hash
          value.to_hash
        elsif value.nil? or Array(value).empty?
          {}
        else
          raise ArgumentError, "invalid value for Hash: #{value}"
        end
      end
    end

Thanks for your consideration.
----------------------------------------
http://redmine.ruby-lang.org/issues/show/3131
Posted by Yukihiro Matsumoto (Guest)
on 2010-04-21 15:29
(Received via mailing list)
Hi,

In message "Re: [ruby-core:29644] [Feature #3131] add Kernel#Hash() 
method like Kernel#Array()"
    on Tue, 20 Apr 2010 13:36:00 +0900, Suraj Kurapati 
<redmine@ruby-lang.org> writes:

|To avoid delaying this request forever due to unnecessary features,
|I have narrowed the requirements for Kernel#Hash() to the following:
|
|Hash() must convert (1) nil, (2) Hash, and (3) empty Array into Hash.

Sounds reasonable.  But the new feature window for 1.9.2 was closed.
So, I will consider (positively) adding this feature after 1.9.2 
release.

              matz.
Posted by Suraj Kurapati (Guest)
on 2010-04-23 02:56
(Received via mailing list)
Issue #3131 has been updated by Suraj Kurapati.


Hi,

Matz wrote:
> I will consider (positively) adding this feature after 1.9.2
> release.

Thanks Matz!  In the mean time, I have created a gem with this
functionality so that people can start using it, if they wish:

  http://rubygems.org/gems/kernel_hash

The source code (and unit tests) is available here:

  http://github.com/sunaku/kernel_hash

Cheers.
----------------------------------------
http://redmine.ruby-lang.org/issues/show/3131
Posted by Suraj Kurapati (Guest)
on 2010-05-25 08:58
(Received via mailing list)
Issue #3131 has been updated by Suraj Kurapati.


Hi,

Please set the "Done %" for this issue to 80%.

The remaining 20% is for (possibly) rewriting
my proposed Kernel#Hash() Ruby code in C.

Thanks for your consideration.
----------------------------------------
http://redmine.ruby-lang.org/issues/show/3131
Posted by Run Paint Run Run (Guest)
on 2010-09-02 16:03
Attachment: kernel-hash.patch (2,06 KB)
(Received via mailing list)
Issue #3131 has been updated by Run Paint Run Run.

File kernel-hash.patch added

I believe the attached patch reflects the consensus between matz and 
Suraj. The only material difference is that a TypeError is raised 
instead of an ArgumentError for consistency with Integer(), Float(), 
etc.
----------------------------------------
http://redmine.ruby-lang.org/issues/show/3131
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.