How to ducktype a Hash?

S

Sean O'Dell

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
 
S

Sean O'Dell

Hi,

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

Florian Gross wrote in [ruby-talk:102433]:
obj.respond_to?:)keys) # ? :)

I'd prefer :each_pair.

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
 
D

Dave Burt

It seems to me that listing (#keys) and iterating through (#each_pair) its
values is a key (excuse the pun) part of a hash's job.

Then again, maybe your hash-like objects aren't hashes in this way. The
question changes if you change the definition of "hash-like".

Is it un-rubyish to use #is_a to do this? i.e. define a module or superclass
for your hash-likes? It may even be useful to include some of this extra
hash-related functionality in a mixin; e.g. define #keys and get #each_pair
for free.

Sean O'Dell said:
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) # ? :)

I'd prefer :each_pair.

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
 
A

Ara.T.Howard

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

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
--
===============================================================================
| 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
===============================================================================
 
S

Steven Grady From:

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?

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

Robert Klemme

Maybe I got something wrong here, but I thought the idea of duck typing was
to just use the instance as a hash and get bitten if it's not. After all,
either way an exception will be thrown. If you don't throw an exception you
can still catch NoSuchMethodEx and treat it appropriately.

Regards

robert
 
G

gabriele renzi

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


why do you need to say 'it is hash like' ?
Wo'nt it be easyer to say 'I need this methods, so I'll just check
them' ?

BTW, probably the simpler solution is :

x.methods =={}.methods
:)
 
G

gabriele renzi

il Sat, 5 Jun 2004 04:59:27 +0000 (UTC), Steven Grady From:
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?

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
 
D

David A. Black

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
 
S

Sean O'Dell

Well, what exactly do all your hash-like objects have in common that
is not present in any other object? :keys is a pretty good identifier
for a hash... since I know of no other data structure that has a key
(mind you, I said "_I_ know of", there could well be one that I don't
know). .

The problem is, there's no definition of what a hash-like object really is.
If there were something I could depend on, I'd check respond_to? for that.
For my own personal uses, all I care about is [] and []=.

Sean O'Dell
 
S

Sean O'Dell

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

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
 
S

Sean O'Dell

On Friday 04 June 2004 22:03, (e-mail address removed), (e-mail address removed),
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

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

Sean O'Dell
 
S

Sean O'Dell

Maybe I got something wrong here, but I thought the idea of duck typing was
to just use the instance as a hash and get bitten if it's not. After all,
either way an exception will be thrown. If you don't throw an exception
you can still catch NoSuchMethodEx and treat it appropriately.

The problem isn't that the object doesn't respond to the methods I need, it's
that it DOES respond to the methods I need, but the methods don't do what I
expect them to do. In this case, duck-typing simply doesn't work for me. I
found this error through duck-typing, but it existed for weeks before I
realized that some objects were quietly trashing sections of data I was
passing around, because strings, arrays and others all respond to [] and []=,
but DON'T contain objects quite the same way hashes do.

I just don't like this duck-typing business. I can handle dynamic typing, but
I wish there were something more solid about the typing, at least a way to
know when an object implements a certain interface or not, so I can tell an
array-like object from a hash-like object.

Sean O'Dell
 
D

Dave Thomas

I just don't like this duck-typing business. I can handle dynamic
typing, but
I wish there were something more solid about the typing, at least a
way to
know when an object implements a certain interface or not, so I can
tell an
array-like object from a hash-like object.

Perhaps you could design the interface to your classes so that the
distinction is either explicit or irrelevant.


Cheers

Dave
 
S

Sean O'Dell

Perhaps you could design the interface to your classes so that the
distinction is either explicit or irrelevant.

It's not my classes that are the problem, it's all of the other objects that
respond to [] and []=, but which aren't hash-like (they're array-like, and
even then it's anyone's guess as to the functionality).

Sean O'Dell
 
G

George Ogata

Sean O'Dell said:
The problem isn't that the object doesn't respond to the methods I
need, it's that it DOES respond to the methods I need, but the
methods don't do what I expect them to do. In this case,
duck-typing simply doesn't work for me. I found this error through
duck-typing, but it existed for weeks before I realized that some
objects were quietly trashing sections of data I was passing around,
because strings, arrays and others all respond to [] and []=, but
DON'T contain objects quite the same way hashes do.

I thought the idea was that if you unit test each piece as you write
it, these sorts of things are usually caught in time.
I just don't like this duck-typing business. I can handle dynamic
typing, but I wish there were something more solid about the typing,
at least a way to know when an object implements a certain interface
or not, so I can tell an array-like object from a hash-like object.

As others have suggested, you don't HAVE to use duck-typing, but if
you choose that path, you need to provide your own type checks, and
shove all your classes in the right place in the right heirarchies.
However, anecdotal evidence (my own and by what others have said here
before) suggests to me that usually type checks have been weened from
in favor of a good unit test. Hence, I imagine, the lack of
strict-typing facilities in the language.
 
J

Jeff Mitchell

--- Sean O'Dell said:
Perhaps you could design the interface to your classes so that the
distinction is either explicit or irrelevant.

It's not my classes that are the problem, it's all of the other objects that
respond to [] and []=, but which aren't hash-like (they're array-like, and
even then it's anyone's guess as to the functionality).

Could you use explicit names such as #lookup and #store ? I realize it's
not as convenient as [], but the problem is that [] is overloaded with meaning.
Perhaps that's what Dave is suggesting.

Thus you'd add #lookup and #store to Hash and all things Hash-like.
With these explicit names you can duck-type without running into geese
and other imposters.





__________________________________
Do you Yahoo!?
Friends. Fun. Try the all-new Yahoo! Messenger.
http://messenger.yahoo.com/
 
D

Dave Thomas

It's not my classes that are the problem, it's all of the other
objects that
respond to [] and []=, but which aren't hash-like (they're array-like,
and
even then it's anyone's guess as to the functionality).

Then it's not your problem! Code on, young turk.


Cheers

Dave
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top