How to ducktype a Hash?

Let me just say that Sean, despite his protestations, doesn't really
want to check that something is "hash-like". He wants to check that
something is "map-like". Forget fetch, store, , etc. A map has two
essential properties: "keys" and "values". OK, we can all go home now
:slight_smile:

Gavin

ยทยทยท

On Monday, June 7, 2004, 11:27:41 PM, David wrote:

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

Sean O'Dell wrote:

ยทยทยท

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

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

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.

Okay, you are right. PStore is the first example that comes to my mind:
It can act like a hash but doesn't have #to_hash. :confused:

--
Rene van Bevern (RvB) <rvb@pro-linux.de>
http://www.pro-linux.de -- http://www.rvb-web.de

Such an abstraction could give a lazy-loading Hash, as in

  class DBAbstraction
    def to_hash
      Hash.new { |hash, key|
        hash[key] = expensive_lookup(key)
      }
    end
  end

So when you call #to_hash in the first place, it's empty. Each key
you call results in a calculation. All unbeknownst to the user of the
hash.

Gavin

ยทยทยท

On Sunday, June 13, 2004, 3:30:38 AM, Sean wrote:

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.

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.

[ot]
I'm getting more convinced every day: would'nt be nice to have some
kind of global matrix of conversion bettween types and something on
the line of an 'as' operator?

ยทยทยท

il Sun, 13 Jun 2004 16:56:13 +0900, Jean-Hugues ROBERT <jean_hugues_robert@yahoo.com> ha scritto::

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.

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). .

8< ----- snip -----

ยทยทยท

On Sat, 5 Jun 2004 11:15:37 +0900, Sean O'Dell <sean@celsoft.com> wrote:

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

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" <sean@celsoft.com> wrote in message
news:200406041915.32644.sean@celsoft.com...

> 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.

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

ยทยทยท

On Friday 04 June 2004 18:34, nobu.nokada@softhome.net wrote:
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
:slight_smile:

ยทยทยท

il Sat, 5 Jun 2004 11:15:37 +0900, "Sean O'Dell" <sean@celsoft.com> ha scritto::

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

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

This is the solution I am going with now. In fact, if Ruby itself had this
sort of "interface identification" built-in, it would suit me perfectly. I
don't believe that respond_to? really tells you much about an object's
interface. Two objects can respond to the same method name, but do
COMPLETELY different things. Duck typing doesn't work, and checking
respond_to? doesn't work. The only way to REALLY know if an object
implements a certain interface is if you can positively identify it directly.
Somehow, the object has to say "I implement the hash interface." Whether
that's just a simple flag, or if Ruby can somehow match it's methods to an
interface description, or whatever, I don't care. All I want to know is if
an object implements a certain interface. I don't care about ancestry, what
methods it responds to, and I don't like just calling the object's methods
and crossing my fingers. Errors slip through quietly like that, and except
for people who don't really care about that sort of thing, it doesn't work.
It just doesn't.

  Sean O'Dell

ยทยทยท

On Saturday 05 June 2004 15:03, Ara.T.Howard wrote:

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 HashLikeA
     def is_hashlike?; true; end
     ...
   end

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:

Hi --

> 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

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)

But if being a Hash instance is really where all this is going, then
it's probably just as well to cut to the chase (#is_a?).

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 think the 'is a' of 'is a duck' is the 'is a' of #is_a?, if
that makes any sense :slight_smile: This is perhaps a wrinkle in the metaphor:
the phrase "... then it is a duck" opens the door a bit to saying,
"Well, then, if this is an 'is a' question, why not just use #is_a? I
think that the 'duck' of "then it is a duck" is actually more of a
virtual creature. I sort of translate the phrase in my mind into
something like:

  If you want something that quacks and waddles, and the thing you've
  got quacks and waddles, then you've got what you want and may
  proceed.

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

OK... but I think the method approach is more streamlined. The way
I've written it above is a bit bulky, but I could slim it down:

  v = obj.get_by_key(k) rescue raise UnHashlikeError, "Unhashlike"

or even just

  v = obj.get_by_key(k)

and let the caller worry about it. I think this is the most direct
route to the heart of the matter, which is whether the method is
present. Otherwise you're just adding a step -- checking for
hashlike-ness -- when you could fold that step into the method call.

(I'm still not really happy with any of these solutions, including
mine, that depend on modifying Hash.)

David

ยทยทยท

On Sun, 6 Jun 2004, Ara.T.Howard wrote:

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

--
David A. Black
dblack@wobblini.net

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

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

Guess, you will be happy if Ruby can do some like ...

obj.respond_to?(Hash::)
or
obj.respond_to?(Foo::)

Isn't it ?

Vladare

Richard Kilmer wrote:

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

1) [...]

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

Rich,

I've been watching this thread and I think you've hit the nail on the head. Sean seems to want semantic equivalence, but is using a syntax which is overloaded out of the box. Duck typing is based on syntax matching. It seems to me that the only way to get semantic equivalence without using type cues or explicit testing is to steer clear of overloaded operators and methods, so that syntax reflects semantics. This is what several others were suggesting when they talked about using hash's alternate method names in place and =.

--paul

"Gavin Sinclair" <gsinclair@soyabean.com.au> schrieb im Newsbeitrag
news:1482033218333.20040608004534@soyabean.com.au...

ยทยทยท

On Monday, June 7, 2004, 11:27:41 PM, David wrote:

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

Let me just say that Sean, despite his protestations, doesn't really
want to check that something is "hash-like". He wants to check that
something is "map-like". Forget fetch, store, , etc. A map has two
essential properties: "keys" and "values". OK, we can all go home now
:slight_smile:

Well, you can even view an Array as map like: keys are integers and values
whatever you like.

Kind regards

    robert

Whatever you need to call it, I'm up for it. =)

  Sean O'Dell

ยทยทยท

On Monday 07 June 2004 07:47, Gavin Sinclair wrote:

On Monday, June 7, 2004, 11:27:41 PM, David wrote:
> I think what we may be running into is the possibility that
> "ducktyping a Hash" is in a sense a contradiction in terms.

Let me just say that Sean, despite his protestations, doesn't really
want to check that something is "hash-like". He wants to check that
something is "map-like". Forget fetch, store, , etc. A map has two
essential properties: "keys" and "values". OK, we can all go home now

It's about time someone finally admitted I'm right. I'm going to go tell my
wife again that I'm right, and now I have proof.

  Sean O'Dell

ยทยทยท

On Saturday 12 June 2004 10:43, Rene van Bevern (RvB) wrote:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Sean O'Dell wrote:
> On Saturday 12 June 2004 04:23, Rene van Bevern wrote:
>> Use the method #to_hash instead. All hash-like objects should be able to
>> give a hash-representation of themselves.
>
> 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.

Okay, you are right. PStore is the first example that comes to my mind:
It can act like a hash but doesn't have #to_hash. :confused:

I don't see how this works. When you call to_hash, no arguments are provided,
so how could you use the key value there? I've also never seen the block
parameter to Hash.new. Not that this changes anything regarding positive
identification of a class' purpose, but it's very interesting. Is this all
new? My Pragmatic Programmer's Guide must already be far out of date.

  Sean O'Dell

ยทยทยท

On Saturday 12 June 2004 16:48, Gavin Sinclair wrote:

On Sunday, June 13, 2004, 3:30:38 AM, Sean wrote:
> 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.
>
> 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.

Such an abstraction could give a lazy-loading Hash, as in

  class DBAbstraction
    def to_hash
      Hash.new { |hash, key|
        hash[key] = expensive_lookup(key)
      }
    end
  end

So when you call #to_hash in the first place, it's empty. Each key
you call results in a calculation. All unbeknownst to the user of the
hash.

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

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

ยทยทยท

On Friday 04 June 2004 20:48, Claus Spitzer wrote:

On Sat, 5 Jun 2004 11:15:37 +0900, Sean O'Dell <sean@celsoft.com> wrote:

> 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.
>
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). .

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 :slight_smile:

This is even worse than object.kind_of(Hash). The whole point of "duck typing" (as I understand it) is that you don't check if an object has certain methods. You just use them. Ruby will throw an error if there's a problem.

The only case where it is advisable to use a form of :responds_to is when you want to have different functionality based on the kind of object that was passed in. A good use of this concept uses as few checks as possible to determine the "kind" (I'm using the term loosely here) of object.

Perhaps the question you should be asking if you have one method that does multiple things based of the "kind" of object is, is your design is flawed? Perhaps your objects themselves should know how to do whatever operation your method that does multiple things does.

ยทยทยท

--
John

This is the solution I am going with now. In fact, if Ruby itself had this
sort of "interface identification" built-in, it would suit me perfectly. I
don't believe that respond_to? really tells you much about an object's
interface. Two objects can respond to the same method name, but do
COMPLETELY different things. Duck typing doesn't work, and checking
respond_to? doesn't work. The only way to REALLY know if an object
implements a certain interface is if you can positively identify it directly.
Somehow, the object has to say "I implement the hash interface." Whether
that's just a simple flag, or if Ruby can somehow match it's methods to an

A protocol imposes constraints to the acceptable behavior of the object, so
as you correctly pointed out, the signatures alone can't suffice. I
believe the current state of the art can discover many implicit
invariants in the code, but it can't infer them all. Even if it could,
at some point you might have some invariants that hold only due to the
particular implementation used, it is still up to the programmer to
specify whether some invariant belongs to the interface or is just a
coincidence.

Therefore, what you seem to want still requires the programmer to tag the
objects somehow.

Once we get to this point, we can think of ways to do it. There's two
things to consider: tagging objects and checking for some tag.
One can trivially use Ruby's mix-in mechanism to declare conformance
with a given interface, and then use some magic to allow

def_typed :my_method, HashProtocol, FooProtocol do |foo, bar|
  ... foo, bar have been declared to satisfy HashProtocol & FooProtocol
end

or something like
  typesig HashProtocol, FooProtocol # Types for next defined method
  def my_method(foo, bar)

The latter (and many other ways to do type checking) is implemented in
http://people.freebsd.org/~eivind/ruby_types/types.rb .

Regarding including this in the language:
I have argued above that ruby wouldn't be able to do internally much more
than the current solutions (in particular, it is also possible to make
sure that method redefinition doesn't break conformity with a declared
interface in pure-Ruby/C-extension solutions). If it won't be any more
powerful, the possible advantages that could justify including it I can
think of are
(1) convenience
(2) speed
(3) sanctioning this practice as belonging to "the Ruby way"

Regarding (3), it is up to matz to define what is and what isn't Ruby,
so we can't comment.

As for (1), Ruby's syntax is "extensible" thanks to blocks, as shown
in http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/99660 .
We'd have to compare syntaxes at some point, but it's not clear a-priori
that a sanctioned syntax in the core must be necessarily better (i.e.
a good solution doesn't necessarily require changes in the parser).

Finally, as far as speed is concerned:
in [85895], matz explains that he doesn't know how to make interface checking
efficient. In [85888] you proposed an interesting interface checking
system and concluded that "Performance hit at runtime is merely a very short
interface table lookup". However, I believe you didn't consider the
following:
* per-object conformity tables are very expensive, memory-wise: one
  additional word per object pointing to the table (if you don't put
  it in the R* structure and store it in the iv_table instead, it'll be
  slower) , plus the table itself.
* per-class conformity tables would have a lower mem. impact, but make
  singleton classes a bit more complex to handle and most importantly
  would make interface checking slower cause you'd have to walk up the
  inheritance chain (caching couldn't be as effective as method caching
  cause there's more objects than distinct methods)

In other words, there's no real way to implement interface checking
much faster than http://mephle.org/StrongTyping/\.

That being said, in the future it might be possible to do constraint
propagation (+ partial evaluation) at compile/parse time + method
specialization, which could make everything significantly faster.

Summarizing, there's arguably little gain in adding this sort of interface
checking to Ruby's core _as of now_. There's a number of solutions that
work fairly well and some that are as fast as you can get today.

You have stated before on this thread that tagging objects is a "kludge";
I cannot agree with that, or more precisely, I don't see it as any
worse than the proposed modifications to Ruby we've seen in the past,
since tagging is about as efficient as they would be, and the available
"interface tagging" implementations have pretty convenient syntaxes
(although that's somewhat subjective, but I think we can agree on the fact
that the "best" syntax doesn't necessarily involve changes in the parser).

interface description, or whatever, I don't care. All I want to know is if
an object implements a certain interface. I don't care about ancestry, what
methods it responds to, and I don't like just calling the object's methods
and crossing my fingers. Errors slip through quietly like that, and except
for people who don't really care about that sort of thing, it doesn't work.

If you need a solution that badly, I'd recommend that you use types.rb
(more flexible) or StrongTyping (faster) for the time being.
I don't think Ruby will do this "natively" for some time...

It just doesn't.

It is my understanding that some large systems have been implemented in
Smalltalk; I'd like to know if they solved those problems through
interface declaration + checking, more stringent procedures or some
other technical solution.

PS: I am personally more interested in concrete type discovery (for speed)
than in generic type inference.

ยทยทยท

On Sun, Jun 06, 2004 at 09:36:25AM +0900, Sean O'Dell wrote:

--
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Tut mir Leid, Jost, aber Du bist ein unertraeglicher Troll.

Was soll das? Du *beleidigst* die Trolle!
  -- de.comp.os.unix.linux.misc

Hi,

This may be somehow stupid but what about simply inheriting
from Hash ?

In the worst case you aren't going to use the hash default
implementation at all, because you would provide your own
implementation for the storage. But that case is not that bad,
because I suspect that the overhead is very very small.

class MyObject < Hash
ย ย def [](key)
ย ย ย ย my_ultra_efficient_get( key)
ย ย end
end

Then you can kind_of? Hash as usual.

End-of-trick

That does not solve the more general issue where Interface
is distinct from Implementation.

OTOH I believe that ducktyping is not about Interfaces.
To me, it is more about service providers not checking
types and handling exceptions in a gentle way. What
the service *provider* expects is part of the contract and,
as an example, requiring a Hash is much less tolerant
that requiring something that can [](key) and []=(k,v).

If the service *user* does not respect the contract, it is
its responsability, not the provider's one.

i.e. If you provide something that does not implement
[](key) then don't expect thing to work.

As a provider, you want to make it clear that it is
the user that did not respect the contract, hence the
need for good exception handling.

Yours,

Jean-Hugues

ยทยทยท

-------------------------------------------------------------------------
Web: http://hdl.handle.net/1030.37/1.1
Phone: +33 (0) 4 92 27 74 17