Hashing across different types

Hello, I'm trying to redefine the way a hash works for an object so that
other types will hash to the same bucket. For example:

class A

  attr :name, true

  def eql?( another )
    return true if self.hash == another.hash
  end

  def hash
    @name.hash
  end

  def to_s
    @name.to_s
  end

end

a = A.new
h = Hash.new

a.name = "Bob"
h[ a ] = "foo"
print "Value: " + h[ "a" ].to_s + "\n"

The values of "a".hash and of a.hash are the same value (100), so
wouldn't h[ "a" ] be the same as h[ a ]?

The result of running the above code is: "Value: " (h[ "a" ] returns
nil). Anyone have any suggestions on how I can make this work? Thanks
much.

Nate

Hi,

At Thu, 19 Aug 2004 00:33:55 +0900,
Nate Smith wrote in [ruby-talk:109688]:

a.name = "Bob"

  h["Bob"] = "foo"
  print "Value: " + h[a].to_s + "\n"

works as you expect. Note that String#eql? checks if classes
are same, therefore this doesn't work.

  h[a] = "foo"
  print "Value: " + h["Bob"].to_s + "\n"

···

--
Nobu Nakada

Sorry, I made a small mistake in what I sent out. Instead of

print "Value: " + h[ "a" ].to_s + "\n"

I meant:

print "Value: " + h[ "Bob" ].to_s + "\n"

So that "Bob" and the variable a would have the same hash value. I don't
think that changes anything though.

Nate

···

On Wed, 2004-08-18 at 11:48, nobu.nokada@softhome.net wrote:

Hi,

At Thu, 19 Aug 2004 00:33:55 +0900,
Nate Smith wrote in [ruby-talk:109688]:
> a.name = "Bob"
  h["Bob"] = "foo"
  print "Value: " + h[a].to_s + "\n"

works as you expect. Note that String#eql? checks if classes
are same, therefore this doesn't work.

I've recently started using Ruby, coming from a C++/Java background.

And while there where some idiosyncracies, by and large I was able to be
very productive very quickly.

The application has evolved from a simple script (in the sense that
everything "looks global") to something a bit more complex, with
refactorings towards using objects, a "Test-First-After-The-Fact" approach
:-), and to factoring out library-like elements.

Now, I'm aware that there's always a discussion about strong vs. weak,
static vs. dynamic. The last time I had an opinion about it I had no good
answer to the claim that unit-tests lessen the need for static type
checking.

Now that I have gulped down the basics of ruby, I'm starting writing unit
tests, from the point of view of "what would a user of this class expect".
And I'm running into what seems to be a fundamental question, and my
googling so far hasn't turned up any satisfactory answer:
When I define a method in a class, let's say initialize(categories, data)
for the sake of argument: In Java etc. I can see from the method definition
that categories is an ordered set, and data is a Map (and if that info is
not sufficient, javadoc can be used to explain in more detail what is
expected, but I'll leave that out for the moment, it's not really key to the
question).
Of course the first step would be to find a good name (at the very least
"data" is a bit too generic). But what next? How does someone who writes an
API communicate that it makes no sense to send "1" to the categories.
Apparently the unit tests and/or dbc encompass the specification, but does
rdoc or some tool extract any information from them?

Am I the first person to run in this problem? If not, what are other
people's solutions? Do you just look at the source code of any library you
use?

I'm asking this from both points of view:

Many times I have run into some library where I was simply asking myself
"what exactly do I have to put into these parameters to get the method to do
what I want?" More specifically, I had this problem in parts of the REXML
library.

And from the other perspective, what is the Ruby Way (tm) to document
methods to users of your API/framework (or simply your class)?

Actually, it *is* key to the question, as it's (basically) the Ruby
answer without using external mechanisms[1] like StrongTyping,
csinterface, or other mechanisms. Look at Diff::LCS as an example. The
main method is Diff::LCS.diff(seq1, seq2, callback =
Diff::LCS::DiffCallback). If you know what 'diff' does, then you'll be
able to make a good guess that you'll get something back similar to
'diff' when you pass in seq1 or seq2. But what are seq1 and seq2,
precisely? According to my documentation, they are ordered sequences.
I should be a bit more accurate in the definition, as they do require
random access under the current implementation, but they must be
either String-like or Array-like (Array-like works best, because
Strings work on a per-character basis).

The more confusing part is the callback parameter. There's absolutely
no way that I could meaningfully define the callback on the parameter
list, as it's a truly duck-typing situation. Using the #sdiff, I could
come up with a MatchingCallback that would only return those lines
that are considered equivalent. The only sensible solution here is
documentation.

My first step for any library I use is to look over its documentation
and examples to see basic usage. Preferably example use. Most of the
folks who have written libraries for Ruby have been sensible in their
choices, and they "make sense." After that, I look at the source if
I'm still confused.

-austin
[1] External to Ruby itself. rdoc and ri are now part of the Ruby distribution.

···

On Thu, 19 Aug 2004 02:26:59 +0900, Nicolai Czempin <nicolai.czempin@alcatel.de> wrote:

Now that I have gulped down the basics of ruby, I'm starting writing unit
tests, from the point of view of "what would a user of this class expect".
And I'm running into what seems to be a fundamental question, and my
googling so far hasn't turned up any satisfactory answer:

When I define a method in a class, let's say initialize(categories, data)
for the sake of argument: In Java etc. I can see from the method definition
that categories is an ordered set, and data is a Map (and if that info is
not sufficient, javadoc can be used to explain in more detail what is
expected, but I'll leave that out for the moment, it's not really key to the
question).

--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

Oh, great, hidden inside another thread... sorry. How do I get it out?
Copy-Pasting the text and posting again and then CANCELing? Sigh..

"Nicolai Czempin" <nicolai.czempin@alcatel.de> wrote in message
news:<007b01c48548$8d37f250$51c6cc95@bln.sel.alcatel.de>...

···

I've recently started using Ruby, coming from a C++/Java background.

Nicolai wrote, in part:

Many times I have run into some library where I was simply asking myself
"what exactly do I have to put into these parameters to get the method
to do what I want?" More specifically, I had this problem in parts of
the REXML library.

And from the other perspective, what is the Ruby Way (tm) to document
methods to users of your API/framework (or simply your class)?

Regarding your example of initialize, I tend to do this.

···

#
    # Detailed usage example...
    #
  class Foo
      # (String) blah blah blah
    attr_reader :name
      # (Hash: Symbol -> Set) blah blah blah
    attr_reader :categories
      # (IO-like: responds to ...) blah blah blah
    attr_reader :output

    def initialize(name, output)
      ...
    end

    def add_category(id, thing)
      @categories[id] ||= Set.new
      @categories[id] << thing
    end
  end

My point: if you provide a decent usage example, then people can read that
and see what they need to do to work with the class. Give some nitty
gritty on the attributes, because they are usually key to understanding
the class. Then the methods will often not need documenting at all.

Cheers,
Gavin