How to ducktype a Hash?

dblack@wobblini.evault.com
> Richard Kilmer [mailto:rich@infoether.com] :
> > Oops...sorry...you are right...it would have to be:
> >
> > f.{Array}['rich']
> >
> > to make it explicit that you are grouping the {} with the
> > method name. This is only an issue for the operator'ish methods
> > because methods require the dot in them already.
>
> Maybe:
>
> f<Array>['rich']
> f.<Person>[firstname]
>
> It's ugly enough to discourage its use, but it also calls
to mind the
> syntax for C++ templates (for good or ill) while not being
> currently-legal Ruby.

I think it has to be assumed that if Matz adds any type-related stuff,
it will get very heavy use, ugly or not. Luckily there's little or no
precedent for Matz adding ugly stuff :slight_smile: but I think this is a case
where people who want to use it are not going to be deterred by how it
looks, so I wouldn't want to rely on that effect.

Well, I still think that this is probably a good compromise, as (1) it
isn't legal Ruby in 1.8, and (2) it will definitely raise warning
hackles to the people who *don't* use it. I seem to recall reading
something in the last year or so that suggests that Matz did add
something to the language that was either *hard* or *ugly* because he
wanted it to be used rarely, but available. I don't remember what it
was.

-austin

···

On Tue, 8 Jun 2004, Austin Ziegler wrote:

--
austin ziegler * austin.ziegler@evault.com

Hi --

···

On Tue, 8 Jun 2004, Austin Ziegler wrote:

> dblack@wobblini.evault.com
> On Tue, 8 Jun 2004, Austin Ziegler wrote:
> > Richard Kilmer [mailto:rich@infoether.com] :
> > > Oops...sorry...you are right...it would have to be:
> > >
> > > f.{Array}['rich']
> > >
> > > to make it explicit that you are grouping the {} with the
> > > method name. This is only an issue for the operator'ish methods
> > > because methods require the dot in them already.
> >
> > Maybe:
> >
> > f<Array>['rich']
> > f.<Person>[firstname]
> >
> > It's ugly enough to discourage its use, but it also calls
> to mind the
> > syntax for C++ templates (for good or ill) while not being
> > currently-legal Ruby.
>
> I think it has to be assumed that if Matz adds any type-related stuff,
> it will get very heavy use, ugly or not. Luckily there's little or no
> precedent for Matz adding ugly stuff :slight_smile: but I think this is a case
> where people who want to use it are not going to be deterred by how it
> looks, so I wouldn't want to rely on that effect.

Well, I still think that this is probably a good compromise, as (1) it
isn't legal Ruby in 1.8, and (2) it will definitely raise warning
hackles to the people who *don't* use it. I seem to recall reading
something in the last year or so that suggests that Matz did add
something to the language that was either *hard* or *ugly* because he
wanted it to be used rarely, but available. I don't remember what it
was.

I agree that that can work in principle, but I think it would backfire
with this.

David

--
David A. Black
dblack@wobblini.net

Austin Ziegler wrote:

<snip>

I seem to recall reading
something in the last year or so that suggests that Matz did add
something to the language that was either *hard* or *ugly* because he
wanted it to be used rarely, but available. I don't remember what it
was.

I think you're reffering to needing a $ in front of global variables. IIRC this is to discourage the use of globals.

···

--
Mark Sparshatt

Maybe:

f<Array>['rich']
f.<Person>[firstname]

It's ugly enough to discourage its use, but it also calls

to mind the

I missed what this syntax (and the other proposals) is supposed to accomplish and the threading in this topic thread is wonky enough so that I can't find the parent messages. Could someone fill me in.

···

--
-- Jim Weirich jim@weirichhouse.org http://onestepback.org
-----------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)

dblack@wobblini.evault.com

Richard Kilmer [mailto:rich@infoether.com] :

Oops...sorry...you are right...it would have to be:

  f.{Array}['rich']

to make it explicit that you are grouping the {} with the
method name. This is only an issue for the operator'ish methods
because methods require the dot in them already.

Maybe:

  f<Array>['rich']
  f.<Person>[firstname]

It's ugly enough to discourage its use, but it also calls

to mind the

syntax for C++ templates (for good or ill) while not being
currently-legal Ruby.

I think it has to be assumed that if Matz adds any type-related stuff,
it will get very heavy use, ugly or not. Luckily there's little or no
precedent for Matz adding ugly stuff :slight_smile: but I think this is a case
where people who want to use it are not going to be deterred by how it
looks, so I wouldn't want to rely on that effect.

Well, I still think that this is probably a good compromise, as (1) it
isn't legal Ruby in 1.8

what? it is legal, as far as I can tell:

hash<Hash>[:key]
NoMethodError: undefined method `<' for {:key=>:value}:Hash
         from (irb):26
hash.<Hash>[:key]
TypeError: compared with non class/module
         from (irb):27:in `>'
         from (irb):27

[:key] is interpreted as an array, and the <>s are interpreted as comparison operators.

···

On Jun 7, 2004, at 2:54 PM, Austin Ziegler wrote:

On Tue, 8 Jun 2004, Austin Ziegler wrote:

and (2) it will definitely raise warning
hackles to the people who *don't* use it. I seem to recall reading
something in the last year or so that suggests that Matz did add
something to the language that was either *hard* or *ugly* because he
wanted it to be used rarely, but available. I don't remember what it
was.

-austin
--
austin ziegler * austin.ziegler@evault.com

Mark Sparshatt wrote:

Austin Ziegler wrote:

<snip>

I seem to recall reading
something in the last year or so that suggests that Matz did add
something to the language that was either *hard* or *ugly* because he
wanted it to be used rarely, but available. I don't remember what it
was.

I think you're reffering to needing a $ in front of global variables. IIRC this is to discourage the use of globals.

I always thought that doing finalizers that was made cumbersome to discourage casual use.

···

--
-- Jim Weirich jim@weirichhouse.org http://onestepback.org
-----------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)

Hi --

···

On Tue, 8 Jun 2004, Jim Weirich wrote:

>>>Maybe:
>>>
>>> f<Array>['rich']
>>> f.<Person>[firstname]
>>>
>>>It's ugly enough to discourage its use, but it also calls
>>to mind the

I missed what this syntax (and the other proposals) is supposed to
accomplish and the threading in this topic thread is wonky enough so
that I can't find the parent messages. Could someone fill me in.

Go to http://www.ruby-talk.org/102672 and follow what's nested under
that and you'll get this branch of the thread.

David

--
David A. Black
dblack@wobblini.net

The key is expressing that a method you are defining is semantically
equivalent to a method in another class/module.

Contrived example:

class NameList
  def initialize
    @list =
  end
  def first_name
    @list.first
  end
end

class Person
  attr_reader :first_name
end

class Robot
  def <Person>first_name
    @first_name
  end
end

This says that Robot's first_name method is semantically equivalent to
Person's first_name method (with all that that semantics carries with
it...which may be a lot, and may not be much). You can "cast" the method
call to an instance:

r = Robot.new

Like this:

r.<Person>first_name

But if you did this:

r.<NameList>first_name

It would raise an exception.

And perhaps extend respond_to? to include an (optional) Class/Module name.

r.respond_to?(:first_name) => true
r.respond_to?(:first_name, Person) => true
r.respond_to?(:first_name, NameList) => false

All this is optional of course. Gavin proposed using <...>, I had
originally used {...}

-rich

···

On 6/7/04 7:37 PM, "Jim Weirich" <jim@weirichhouse.org> wrote:

Maybe:

f<Array>['rich']
f.<Person>[firstname]

It's ugly enough to discourage its use, but it also calls

to mind the

I missed what this syntax (and the other proposals) is supposed to
accomplish and the threading in this topic thread is wonky enough so
that I can't find the parent messages. Could someone fill me in.

Hi --

···

On Tue, 8 Jun 2004, Richard Kilmer wrote:

On 6/7/04 7:37 PM, "Jim Weirich" <jim@weirichhouse.org> wrote:

>>>> Maybe:
>>>>
>>>> f<Array>['rich']
>>>> f.<Person>[firstname]
>>>>
>>>> It's ugly enough to discourage its use, but it also calls
>>> to mind the
>
> I missed what this syntax (and the other proposals) is supposed to
> accomplish and the threading in this topic thread is wonky enough so
> that I can't find the parent messages. Could someone fill me in.

The key is expressing that a method you are defining is semantically
equivalent to a method in another class/module.

What happens if the method in the other class or module gets
redefined, with new semantics?

David

--
David A. Black
dblack@wobblini.net

Hi --

>>>> Maybe:
>>>>
>>>> f<Array>['rich']
>>>> f.<Person>[firstname]
>>>>
>>>> It's ugly enough to discourage its use, but it also calls
>>> to mind the
>
> I missed what this syntax (and the other proposals) is supposed to
> accomplish and the threading in this topic thread is wonky enough so
> that I can't find the parent messages. Could someone fill me in.

The key is expressing that a method you are defining is semantically
equivalent to a method in another class/module.

It's interesting; I'm actually having trouble coming up with much in
the way of components of Ruby method semantics. There's number of
arguments... but I'm not sure I can think of anything else. Arguments
are untyped and methods don't have a return type, and whether or not a
method requires a block (another candidate criterion) might depend on
what happens at runtime. So in determining whether two methods are or
are not semantically equivalent (and I assume this has to be
determined statically), what else is there, besides argument count,
that one can compare?

Meanwhile, in spite of this rather large question mark, let me delve
into the syntax stuff, just for fun :slight_smile: (See below....)

Contrived example:

class NameList
  def initialize
    @list =
  end
  def first_name
    @list.first
  end
end

class Person
  attr_reader :first_name
end

class Robot
  def <Person>first_name
    @first_name
  end
end

This says that Robot's first_name method is semantically equivalent to
Person's first_name method (with all that that semantics carries with
it...which may be a lot, and may not be much). You can "cast" the method
call to an instance:

r = Robot.new

Like this:

r.<Person>first_name

But if you did this:

r.<NameList>first_name

It would raise an exception.

I wonder if there's a way to build more organically on the existing
module mechanism, even if more restrictively. For example:

  module X
    def m
      # ...
    end
  end

  class A
    include X # A uses X's actual method m
  end

  class B
    emulate X
    def m # B defines its own method m -- but
      # ... # 'emulate' has committed it to
    end # match the semantics of X's methods
  end # wherever the method names match

  # And per-object (like 'extend'):

  o = Object.new
  o.embody(X) # commits o to X's methods' semantics,
                 # wherever the names match, but does
                 # not actually give o any new methods
  def o.m
    # ...
  end

It's more restrictive than yours in the sense that with mine, you
can't mix-and-match any method call with any class/module reference.
But I don't think that's necessarily bad, and in any case I wanted to
shoot for something with as much visual smoothness and integration as
I could, while still addressing (some or most of) the same issues.

David

···

On Tue, 8 Jun 2004, Richard Kilmer wrote:

On 6/7/04 7:37 PM, "Jim Weirich" <jim@weirichhouse.org> wrote:

--
David A. Black
dblack@wobblini.net

David A. Black wrote:

I missed what this syntax (and the other proposals) is supposed to accomplish and the threading in this topic thread is wonky enough so that I can't find the parent messages. Could someone fill me in.

Go to http://www.ruby-talk.org/102672 and follow what's nested under
that and you'll get this branch of the thread.

Thanks. Now I wish I hadn't asked. :slight_smile:

I know its fun to play "what if" with Ruby syntax and all, but I can't help but think this is using a cannon to swat a fly. And I'm not sure it will solve Sean's problems anyways (which is more about type discovery than type checking).

Actually, I was going to write up a proposal but saw a posting
in ruby-talk:102752 that echoed my idea. We need a mixin module for hashable (similar to Enumerable) that implements the basic functionality of hashes on the basis of a small number of primitives. Then anyone needing hash-like behavior would mixin this module and would get a fully implemented Hash interface.

Advantages:
   * Full set of hash methods for the cost of implementing a small number
     of primitives.
   * Well defined semantics[1] for all the hash methods
   * Easy to check test to see if something implements hash-like
     behavior (obj.is_a?(Hashable)).

I see a need for something like this for IO as well (eg. Readable, Writeable).

···

--
-- Jim Weirich jim@weirichhouse.org http://onestepback.org
-----------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)

What happens if you override the << method on Array to say, just ignore the
parameter? Lots of bad stuff. If you change the semantics of a class at
runtime, you should know the consequences...Ruby allows it, and that is
fine, but "with great power comes great responsibility" :wink:

But to really answer your question, if you say in Ruby 'my foo method is
equivalent to that other classes foo method' then you change the meaning of
the foo method on that class, from Ruby's perspective you are still
equivalent. Its just a hint.

Although, it would be cool to create an internal link from Hash's foo method
with those that declare equivalence, that way if you do this:

class Foo
  def <Hash>(key)
    #...do something 'hashlike'
  end
end

class Hash
  def (key)
    return Time.now
  end
end

Ruby could raise a Warning...

Warning line xxx: Class Foo's method has declared equivalence with Hash's
method, changing this method could have unforeseen consequences.

Or something like that...

-rich

···

On 6/7/04 10:07 PM, "David A. Black" <dblack@wobblini.net> wrote:

The key is expressing that a method you are defining is semantically
equivalent to a method in another class/module.

What happens if the method in the other class or module gets
redefined, with new semantics?

David

I'm working on an typing implementation right now that uses only arity to make
sure that methods still comply with the interface description. That's pretty
much all you need. I wish Ruby reported a little more clearly what
parameters a method takes. The arity values right now are primitive, and
don't tell you how many optional arguments a method takes, doesn't
discriminate between a fixed number of optional arguments and arguments taken
as an array (*param), nor does it report when a &block is a required
parameter. My interface implementation would be helped greatly by more
information. Also, Ruby doesn't called method_added when a method is added
directly to an object with <<.

  Sean O'Dell

···

On Monday 07 June 2004 19:55, David A. Black wrote:

It's interesting; I'm actually having trouble coming up with much in
the way of components of Ruby method semantics. There's number of
arguments... but I'm not sure I can think of anything else. Arguments
are untyped and methods don't have a return type, and whether or not a
method requires a block (another candidate criterion) might depend on
what happens at runtime. So in determining whether two methods are or
are not semantically equivalent (and I assume this has to be
determined statically), what else is there, besides argument count,
that one can compare?

Jim Weirich wrote:

Actually, I was going to write up a proposal but saw a posting
in ruby-talk:102752 that echoed my idea. We need a mixin module for
hashable (similar to Enumerable) that implements the basic functionality
of hashes on the basis of a small number of primitives. Then anyone
needing hash-like behavior would mixin this module and would get a fully
implemented Hash interface.

Advantages:
   * Full set of hash methods for the cost of implementing a small
     number of primitives.
   * Well defined semantics[1] for all the hash methods
   * Easy to check test to see if something implements hash-like
     behavior (obj.is_a?(Hashable)).

I like the idea. Can you propose some details? And can it be called Map
rather than Hashable? I presume you're talking about map semantics,
involving mapping a key to a value, rather than hash semantics, involving
calculating hash codes.

obj.is_a?(Map) reads nicely to me.

I see a need for something like this for IO as well (eg. Readable,
Writeable).

That seems less important than the much-discussed-from-all-angles Hash,
but interesting nonetheless. Again, I'm hungry for details.

Cheers,
Gavin

Hi --

David A. Black wrote:
>>I missed what this syntax (and the other proposals) is supposed to
>>accomplish and the threading in this topic thread is wonky enough so
>>that I can't find the parent messages. Could someone fill me in.
>
> Go to http://www.ruby-talk.org/102672 and follow what's nested under
> that and you'll get this branch of the thread.

Thanks. Now I wish I hadn't asked. :slight_smile:

:slight_smile:

I know its fun to play "what if" with Ruby syntax and all, but I can't
help but think this is using a cannon to swat a fly. And I'm not sure
it will solve Sean's problems anyways (which is more about type
discovery than type checking).

I tend to agree with the cannon point. My first choice, by a wide
margin, would in fact be for no language-level frameworks to be
introduced in this whole area (types, interface compliance, etc.) in
2.0. I would rather see people continue to work on after-market,
pure-Ruby frameworks, and let's see if they prove popular. (This is
in general a good way to go about things, I think, but all the more
important here where we're potentially looking at a major shift in the
center of gravity of the language for a large number of people.)

Actually, I was going to write up a proposal but saw a posting
in ruby-talk:102752 that echoed my idea. We need a mixin module for
hashable (similar to Enumerable) that implements the basic functionality
of hashes on the basis of a small number of primitives. Then anyone
needing hash-like behavior would mixin this module and would get a fully
  implemented Hash interface.

Advantages:
   * Full set of hash methods for the cost of implementing a small number
     of primitives.
   * Well defined semantics[1] for all the hash methods

Where's [1]?

   * Easy to check test to see if something implements hash-like
     behavior (obj.is_a?(Hashable)).

I know I tend to have a knee-jerk anti-is_a? reaction... but I wonder
whether there would be a way to have a method that was analogous to
Enumerable's #each -- maybe #each_key or something. I'm not sure that
makes sense; just thinking out loud.

I see a need for something like this for IO as well (eg. Readable,
Writeable).

I like -able modules a lot. They are Likeable :slight_smile:

David

···

On Tue, 8 Jun 2004, Jim Weirich wrote:

--
David A. Black
dblack@wobblini.net

If you head down this path a bit further (the path of decomposing existing
classes into compositions of modules), you end up with Traits[1]. The
original Trait implementors rebuilt a Squeak standard library using finely
grained traits, to show it was feasible. I've built (at least a shell of) a
Trait implementation in Ruby[2], but you can get by with straight Ruby
modules, as Matz has previously[3] noted.

Of course, its a fair amount of work to reimplement the standard library in
terms of traits (or fine-grained modules). And the documentation effort
would need to be redoubled (classes would have the same topology, but you'd
want to mention how they're composed if you want to leverage that info). Is
it worth it?

[1] http://www.iam.unibe.ch/~scg/Archive/Papers/Scha02bTraits.pdf
[2] http://homepages.ihug.com.au/~naseby/33.html
[3] http://www.ruby-talk.org/blade/92858

David Naseby
http://homepages.ihug.com.au/~naseby/

···

-----Original Message-----
From: dblack@wobblini [mailto:dblack@wobblini]On Behalf Of David A.
Black
On Tue, 8 Jun 2004, Jim Weirich wrote:

> Actually, I was going to write up a proposal but saw a posting
> in ruby-talk:102752 that echoed my idea. We need a mixin module for
> hashable (similar to Enumerable) that implements the basic
functionality
> of hashes on the basis of a small number of primitives. Then anyone
> needing hash-like behavior would mixin this module and would
get a fully
> implemented Hash interface.
>
> Advantages:
> * Full set of hash methods for the cost of implementing a
small number
> of primitives.
> * Well defined semantics[1] for all the hash methods

Where's [1]?

> * Easy to check test to see if something implements hash-like
> behavior (obj.is_a?(Hashable)).

I know I tend to have a knee-jerk anti-is_a? reaction... but I wonder
whether there would be a way to have a method that was analogous to
Enumerable's #each -- maybe #each_key or something. I'm not sure that
makes sense; just thinking out loud.

> I see a need for something like this for IO as well (eg. Readable,
> Writeable).

I like -able modules a lot. They are Likeable :slight_smile:

information. Also, Ruby doesn't called method_added when a method is added
directly to an object with <<.

class Foo; def singleton_method_added(meth); p meth end end

=> nil

f = Foo.new; class << f; def bar; end end

:bar
=> nil

···

On Tue, Jun 08, 2004 at 12:05:41PM +0900, Sean O'Dell wrote:

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

One tree to rule them all,
One tree to find them,
One tree to bring them all,
and to itself bind them.
  -- Gavin Koch <gavin@cygnus.com>

did I already asked you 'please join the ruby buzz at artima.com' ? :slight_smile:

···

il Tue, 8 Jun 2004 21:35:39 +0900, "David Naseby" <david.naseby@eonesolutions.com.au> ha scritto::

David Naseby
http://homepages.ihug.com.au/~naseby/