How to ducktype a Hash?

I need to detect when an object is a hash-like container for other objects,
one which responds to [] and which can index using any object as a value
(string, etc.).

My problem is, respond_to?(:[]) returns true for objects which are array-like
and for strings (both have [] methods). I need to prevent strings, arrays,
and any other object which responds to :[] from getting to this one point in
code, and only allow a hash or hash-like object. The data type at this
particular point in the code comes from a variety of data sources, and there
are lots of ways it could become a string, or an array or theoretically any
object. I need to know when it's a hash or hash-like object, and raise an
exception when it is not. My biggest problem right now is, when it's a
string or an array, the code has no way of knowing if the returned object/nil
is a valid value, or if a "undesirable" object has slipped in and returned
what it likes to return when you call its [] method.

So, how do I positively identify when an object is a hash or at least behaves
like a hash?

  Sean O'Dell

Sean O'Dell wrote:

So, how do I positively identify when an object is a hash or at least behaves like a hash?

obj.respond_to?(:keys) # ? :slight_smile:

is this totally out of the question?

create a module that is a ducktype 'flag' for hashables

   module HashingObject; end

add it to hash - a bit ugly, but does nothing

   class Hash; include HashingObject; end

bless any class you deem good anough with the module

   class MyHashLikeObject
     include HashingObject
     def k
       ...
     end
     def = k
       ...
     end
   end

now you can simply

   idx =
     case obj
       when HashingObject
         ...
       when IndexingObject
         ...
       else
         raise TypeError, obj.class
     end

-a

···

On Sat, 5 Jun 2004, Sean O'Dell wrote:

I need to detect when an object is a hash-like container for other objects,
one which responds to and which can index using any object as a value
(string, etc.).

My problem is, respond_to?(:) returns true for objects which are array-like
and for strings (both have methods). I need to prevent strings, arrays,
and any other object which responds to : from getting to this one point in
code, and only allow a hash or hash-like object. The data type at this
particular point in the code comes from a variety of data sources, and there
are lots of ways it could become a string, or an array or theoretically any
object. I need to know when it's a hash or hash-like object, and raise an
exception when it is not. My biggest problem right now is, when it's a
string or an array, the code has no way of knowing if the returned object/nil
is a valid value, or if a "undesirable" object has slipped in and returned
what it likes to return when you call its method.

So, how do I positively identify when an object is a hash or at least behaves
like a hash?

  Sean O'Dell

--

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
A flower falls, even though we love it; and a weed grows, even though we do
not love it. --Dogen

===============================================================================

How about using the fetch and store methods? These work the same as
Hash# and Hash#=, but are unique to Hash.
Your other hash-like objects might not implement them, but they would
be easy to add.

Nathan

"Sean O'Dell" <sean@celsoft.com> wrote in message news:<200406041715.09691.sean@celsoft.com>...

···

I need to detect when an object is a hash-like container for other objects,
one which responds to and which can index using any object as a value
(string, etc.).

My problem is, respond_to?(:) returns true for objects which are array-like
and for strings (both have methods). I need to prevent strings, arrays,
and any other object which responds to : from getting to this one point in
code, and only allow a hash or hash-like object. The data type at this
particular point in the code comes from a variety of data sources, and there
are lots of ways it could become a string, or an array or theoretically any
object. I need to know when it's a hash or hash-like object, and raise an
exception when it is not. My biggest problem right now is, when it's a
string or an array, the code has no way of knowing if the returned object/nil
is a valid value, or if a "undesirable" object has slipped in and returned
what it likes to return when you call its method.

So, how do I positively identify when an object is a hash or at least behaves
like a hash?

  Sean O'Dell

param.respond_to? '[]' and
param.respond_to? '[]=' and
!param.kind_of? String and
!param.kind_of? Array

Sean O'Dell wrote:

So, how do I positively identify when an object is a hash or at least behaves
like a hash?

Use the method #to_hash instead. All hash-like objects should be able to
give a hash-representation of themselves.

  Rene

Hi,

At Sat, 5 Jun 2004 10:13:44 +0900,
Florian Gross wrote in [ruby-talk:102433]:

> So, how do I positively identify when an object is a hash or at least behaves
> like a hash?

obj.respond_to?(:keys) # ? :slight_smile:

I'd prefer :each_pair.

···

--
Nobu Nakada

You have two requirements: that it respond to , and that it can
index any object. I think you can check these both at run-time with:
    def isHash(o)
  begin o[Object.new] rescue return false end
  return true
    end

Does this meet your needs?

  Steven
"You're way over budget. Can you show me the cause?"
"It depends. Can mirrors reflect your image?"

···

On Sat, 5 Jun 2004, Sean O'Dell wrote:
I need to detect when an object is a hash-like container for other objects,
one which responds to and which can index using any object as a value
(string, etc.).

Hi --

is this totally out of the question?

create a module that is a ducktype 'flag' for hashables

   module HashingObject; end

add it to hash - a bit ugly, but does nothing

   class Hash; include HashingObject; end

bless any class you deem good anough with the module

[...]

now you can simply

   idx =
     case obj
       when HashingObject
         ...
       when IndexingObject
         ...
       else
         raise TypeError, obj.class
     end

I think that could well work in practice, but wouldn't call it duck
typing. You're not asking it to quack up front; you're checking its
module ancestry -- which, I hasten to add, may be exactly what you
want to do, but isn't the same as what a duck typing approach would
lead you to.

Let me try to flesh this out with a companion example:

  class UnHashlikeError < Exception
  end

  module Hashlike
    alias :get_by_key :
  end

  class Hash # probably inadvisable, as Paul Brannan has
    include Hashlike # recently pointed out...
  end

  # ...

  value = begin
            obj.get_by_key(k)
          rescue NoMethodError
            raise UnHashlikeError, "Object isn't hashlike"
          end

or something like that. The basic idea here is: get your ducks in a
row, so to speak, by manipulating the object universe so that a
certain type or subtype of object understands a certain message, then
at runtime, send that message and branch on the consequences.

David

···

On Sat, 5 Jun 2004, Ara.T.Howard wrote:

--
David A. Black
dblack@wobblini.net

Funny, this is similar to an idea I had once about flagging objects as
implementing certain kinds of interfaces. I think this will actually do the
trick for me nicely. I'll just pre-tag all the objects I need to id and then
go from there. Too bad something like this isn't built-in; it would be nice
to get an automatic error when the object type is wrong.

  Sean O'Dell

···

On Friday 04 June 2004 21:43, Ara.T.Howard wrote:

On Sat, 5 Jun 2004, Sean O'Dell wrote:
> I need to detect when an object is a hash-like container for other
> objects, one which responds to and which can index using any object as
> a value (string, etc.).

create a module that is a ducktype 'flag' for hashables

   module HashingObject; end

add it to hash - a bit ugly, but does nothing

   class Hash; include HashingObject; end

bless any class you deem good anough with the module

Nathan Weston wrote:

How about using the fetch and store methods? These work the same as
Hash# and Hash#=, but are unique to Hash.

ObjectSpace.each_object(Module){|m| p m if m.instance_methods.include? "fetch" }

Both Hash and Array have fetch, apparently only Hash has store.

For other potentially unique candidates:

--------------&<--------------
target = Hash
methods = target.instance_methods

classes =
ObjectSpace.each_object(Module){|c| classes << c }
classes.delete target

classes.each{|c| methods -= c.instance_methods }
puts methods.size, methods

=begin
$ ruby unique_interface.rb
15
value?
to_hash
merge!
merge
store
default
default=
default_proc
invert
has_key?
each_value
update
has_value?
rehash
each_key
=end
--------------&<--------------

···

--
(\[ Kent Dahl ]/)_ _~_ _____[ http://www.pvv.org/~kentda/ ]_____/~
  ))\_student_/(( \__d L b__/ Master of Science in Technology )
( \__\_õ|õ_/__/ ) _) Industrial economics and technology management (
  \____/_ö_\____/ (____engineering.discipline_=_Computer::Technology___)

Hi --

param.respond_to? '' and
param.respond_to? '=' and
!param.kind_of? String and
!param.kind_of? Array

That's not duck typing (see Dave's description(s), especially recent
clarification that duck typing isn't about checking things) -- also,
it would run aground on:

  class C
    def
      puts "Hello!"
    end
  end

I think what we may be running into is the possibility that
"ducktyping a Hash" is in a sense a contradiction in terms.

David

···

On Mon, 7 Jun 2004, Dave Burt wrote:

--
David A. Black
dblack@wobblini.net

Other objects also respond to and = which are not Strings or Arrays. The
number of them are potentially infinite, so this is not what I consider a
good solution.

  Sean O'Dell

···

On Monday 07 June 2004 06:13, Dave Burt wrote:

param.respond_to? '' and
param.respond_to? '=' and
!param.kind_of? String and
!param.kind_of? Array

Not necessarily. A database abstraction might act like a hash, but wouldn't
dump entire tables, which could contain tens of thousands of records, as one
big Ruby hash. That isn't positive identification.

  Sean O'Dell

···

On Saturday 12 June 2004 04:23, Rene van Bevern wrote:

Sean O'Dell wrote:
> So, how do I positively identify when an object is a hash or at least
> behaves like a hash?

Use the method #to_hash instead. All hash-like objects should be able to
give a hash-representation of themselves.

This makes a lot of sense to me. It seems to be symmetric
to to_str() too, which is good.

As a matter of fact, my rcr.rb has a to_hash() for Array:

  # Have Array.to_h() return an ArrayAsHash.
  # Please note that aa.to_h().to_a() == aa, which was the initial intend.
  class Array
    def to_h()
      h = ArrayAsHash.new()
      each_index do |ii| h[ii] = self[ii] end
      return h
    end
  end

  # What you get when converting an Array into a Hash, see Array##to_h()
  # It is a Hash with keys that are integer indexes (from 0 up to size of hash).
  class ArrayAsHash < Hash
    def to_a()
      super().sort_by { |(k,v)| k }.collect { |(k,v)| v }
      # ToDo: There must be a faster solution to do that.
    end
  end

  # Have Hash.to_a() return an HashAsArray instead of an Array.
  # Besides the class there are no other difference.
  class Hash
    alias ruby_to_a to_a unless defined? ruby_to_a
    # Returns an array of [key,value] pairs.
    # Please note that h.to_a().to_h() == h for most purposes.
    def to_a()
      HashAsArray.new().replace( ruby_to_a())
    end
    # Returns self. Much like Array##to_a() does.
    def to_h()
      self
    end
  end

Yours,

JeanHuguesRobert

···

At 20:23 12/06/2004 +0900, you wrote:

Sean O'Dell wrote:

So, how do I positively identify when an object is a hash or at least behaves
like a hash?

Use the method #to_hash instead. All hash-like objects should be able to
give a hash-representation of themselves.

       Rene

-------------------------------------------------------------------------
Web: @jhr is virteal, virtually real
Phone: +33 (0) 4 92 27 74 17

In both cases, does that mean that the object has hash-like functionality, or
just that the object responds to those two methods? Is there some definition
somewhere that says "it's a hash if it has these methods?" I actually have
hash-like objects that DON'T respond to either of those two methods, but it
would be easy enough to add fake ones. I hate adding fake methods just to id
a hash interface, it's a kludge.

  Sean O'Dell

···

On Friday 04 June 2004 18:34, nobu.nokada@softhome.net wrote:

Hi,

At Sat, 5 Jun 2004 10:13:44 +0900,

Florian Gross wrote in [ruby-talk:102433]:
> > So, how do I positively identify when an object is a hash or at least
> > behaves like a hash?
>
> obj.respond_to?(:keys) # ? :slight_smile:

I'd prefer :each_pair.

you don't need the begin..end, a method block is an "exception
container" by itself:

def isHash(o)
  o[Object.new]
  true
rescue
  false
end

···

il Sat, 5 Jun 2004 04:59:27 +0000 (UTC), Steven Grady From: <grady@scam.XCF.Berkeley.EDU> ha scritto::

On Sat, 5 Jun 2004, Sean O'Dell wrote:
I need to detect when an object is a hash-like container for other objects,
one which responds to and which can index using any object as a value
(string, etc.).

You have two requirements: that it respond to , and that it can
index any object. I think you can check these both at run-time with:
   def isHash(o)
begin o[Object.new] rescue return false end
return true
   end

Does this meet your needs?

That's a little bit expensive. I'm sure it works, but way too much overhead
for just a type check.

  Sean O'Dell

···

On Friday 04 June 2004 22:03, Steven@ruby-lang.org, Grady@ruby-lang.org, From@ruby-lang.org: wrote:

>On Sat, 5 Jun 2004, Sean O'Dell wrote:
> I need to detect when an object is a hash-like container for other
> objects, one which responds to and which can index using any object as
> a value (string, etc.).

You have two requirements: that it respond to , and that it can
index any object. I think you can check these both at run-time with:
    def isHash(o)
  begin o[Object.new] rescue return false end
  return true
    end

hmmmm... i see where you are coming from, but actualy disagree. the way i see
it duck typing is really not extremely different from interfaces. it's
basically just saying 'this thing is a duck if it quacks like a duck'. in
sean's case he's asking if an object

   quacks (#)

   like (# any_object_not_just_indexes)

   a duck (Hash)

in otherwords he is __exactly__ wanting to know if object posses certain
methods with certain signatures (a # methods which takes any 'ol object for
instance). this is asking if an object implements an interface - albeit a
small one. in fact duck typing has always struck me as objects implemnting
fine grained (and perhaps dynamic) interfaces. my approach is simply this:
ruby can't tell me this efficiently now, so, iff all objects can be known
before runtime, i'll simply mark them. i don't see this as checking ancestry
because one could have easily done this via some other form of marking:

   class Hash
     def is_hashlike?; true; end
   end

   class HashLikeA
     def is_hashlike?; true; end
     ...
   end

   class HashLikeB
     def is_hashlike?; true; end
     ...
   end

etc.

   case obj.respond_to? 'is_hashlike'
     when true
     when false
   end

etc.

in fact. i can't imagine any efficient form of builtin duck typing which
would not be some sort of aggregate method/signature checking - it's simply
too costly to check each method and signature every time. but perhaps i'm
wrong... hopefully in fact :wink:

cheers.

-a

···

On Sat, 5 Jun 2004, David A. Black wrote:

I think that could well work in practice, but wouldn't call it duck
typing. You're not asking it to quack up front; you're checking its
module ancestry -- which, I hasten to add, may be exactly what you
want to do, but isn't the same as what a duck typing approach would
lead you to.

Let me try to flesh this out with a companion example:

class UnHashlikeError < Exception
end

module Hashlike
   alias :get_by_key :
end

class Hash # probably inadvisable, as Paul Brannan has
   include Hashlike # recently pointed out...
end

# ...

value = begin
           obj.get_by_key(k)
         rescue NoMethodError
           raise UnHashlikeError, "Object isn't hashlike"
         end

or something like that. The basic idea here is: get your ducks in a
row, so to speak, by manipulating the object universe so that a
certain type or subtype of object understands a certain message, then
at runtime, send that message and branch on the consequences.

David

--

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
A flower falls, even though we love it; and a weed grows, even though we do
not love it. --Dogen

===============================================================================

I'm going to chime on this thread in two areas:

1) Having a fairly large 10K Ruby framework Running across over 300 machines
I can safely say that Ruby scales fine...and I duck type when it makes sense
and I use kind_of? when it makes sense. The code stresses all aspects of
Ruby to a pretty large extreme (including threading, networking, parsing).
We have about 20 folks now writing Ruby code so its a decent large
contribution (ie. not just one programmer) although I manage the main body
of code. We have had issues over the years in debugging, etc, but the
enormous benefits we get from Ruby so far offset these issues that (although
painful) they are worth it.

2) Sean: It seems like what you are looking for is to check a method for
'semantic equivalence'...that is, you want to say that the and =
methods on an object are semantically equivalent to the and = methods
on Hash. Not that the object is in any way (from and inheritance
perspective) related to a Hash, nor does it actually get the behavior of a
Hash object's and = methods, but when it comes to those two
methods...'quack like a Hash'. Does that sound right? If so, the question
becomes how to express this kind of semantic equivalence both in the
definition of the methods, and the checking with respond_to?

-rich

···

On 6/7/04 9:27 AM, "David A. Black" <dblack@wobblini.net> wrote:

Hi --

On Mon, 7 Jun 2004, Dave Burt wrote:

param.respond_to? '' and
param.respond_to? '=' and
!param.kind_of? String and
!param.kind_of? Array

That's not duck typing (see Dave's description(s), especially recent
clarification that duck typing isn't about checking things) -- also,
it would run aground on:

  class C
    def
      puts "Hello!"
    end
  end

I think what we may be running into is the possibility that
"ducktyping a Hash" is in a sense a contradiction in terms.

David