Injecting methods from one class into another

Sam Roberts wrote:

Quoteing eero.saynatkari@kolumbus.fi, on Wed, Jan 26, 2005 at 07:51:57AM +0900:

Lähettäjä: "George Moschovitis" <george.moschovitis@gmail.com>
Aihe: Re: Injecting methods from one class into another.

I do not think what you want has anything to do with 'duck typing'.

You're forgetting something. It's not "If it quacks...", it's
"If it quacks... and if it walks...". The gist is that as long as
an object has *all* of the (required) characteristics of a type, the
object can be treated as a specimen of that type.

I don't think thats the case at all. I'd like to see you implement
something that "walks like a Hash" by your definition! Make sure you
do all of:

      ==, , =, clear, default, default=, default_proc, delete,
      delete_if, each, each_key, each_pair, each_value, empty?, fetch,
      has_key?, has_value?, include?, index, indexes, indices,
      initialize_copy, inspect, invert, key?, keys, length, member?,
      merge, merge!, rehash, reject, reject!, replace, select, shift,
      size, sort, store, to_a, to_hash, to_s, update, value?, values,
      values_at

And there is no "HashWalk" module you can include to make your class
walk like a Hash, so you might have to copy all those methods...

Yet, there are many objects that are sufficiently like a Hash that you
can use that object in place of a Hash, in particular circumstances. I'd
say that's the more common use of duck-typing.

That's what I said :slight_smile:

If the only requirement one has of a duck is the ability to fly, then for
all intents and purposes, a hawk is a duck. Signor Moschovitis, however,
was essentially claiming that since a hawk can fly and a duck can fly, a
hawk must be a duck (or, if an object responds to one of the methods of
a given type, it should somehow be able to respond to all the others as well).

Duck typing, essentially, means that, /in a particular context/, a
given object has all the characteristics of a given type. For example,
it might be enough for an object to implement and = for it to be
treated as a Hash in a certain context.

As an animal analogy regarding 'injecting' methods, tearing off the
wings of a duck and gluing them to a pig doesn't mean the pig can fly.

There are methods in library classes I would like in my classes. Right
now, I cut and paste. Yes, if those methods were in a module, I could
include them, but they are not. Would "method stealing" always work? Of
course not. But, the methods I want would work!

This is a real example, the specific methods I have copied are from
resolv.rb, DNS#getaddress() ... DNS#getresources() I have copied (I have
my own #each_resource()).

I may try to inherit. But, my class relationship to DNS does NOT model
a "is a" relationship. So, I am abusing inheritance to steal
implementation. Is this so beautiful?

Also, there are methods I don't want, I need to make sure they do not
appear. Also, there are constants that must have a different value in my
class, can I change them? I don't think so.

Really, I just want those methods! But, there is no way to get them in
my class other than copying, or convincing the maintainer to cut his
class into pieces for me. Too bad.

I can see your point: however, a circumstance like this is somewhat exceptional.
Usually such is not possible due to method dependencies or missing variables
or whatever. The 'proper' thing to do would be to factor out such common code
and implement a Module (e.g. Enumerable) with the desired functionality. If
you can't factor it out, it means the implementation should remain separate.

Ruby is still better than the alternatives.

Thanks,
Sam

E

If the only requirement one has of a duck is the ability to fly, then

for

all intents and purposes, a hawk is a duck.

Thats my point :slight_smile:

Signor Moschovitis, however, was essentially claiming that since a

hawk can

fly and a duck can fly, a hawk must be a duck (or, if an object

responds to

of the methods of a given type, it should somehow be able to respond

to all > the > others as well).

never claimed that , I only want to 'inject' the one method from Duck
that is compatible with Hawk. Read my example more carefully please.
-g.

Hi --

Duck typing, essentially, means that, /in a particular context/, a
given object has all the characteristics of a given type. For example,
it might be enough for an object to implement and = for it to be
treated as a Hash in a certain context.

It's not exactly that it's being treated as a Hash -- it's more that,
*like* a Hash, it's being treated as an object that responds to and
=. This is, perhaps, a subtle point, but I think it's key in
getting away from the class-based view. All of the /= objects
converge on the type that can only be described as "the type of
objects that respond to and =". In that sense, Hashes are just
one of infinitely many possible objects that exhibit the behaviors of
that type.

David

···

On Wed, 26 Jan 2005, E S wrote:

--
David A. Black
dblack@wobblini.net

Quoteing eero.saynatkari@kolumbus.fi, on Wed, Jan 26, 2005 at 02:05:44PM +0900:

Sam Roberts wrote:
> Quoteing eero.saynatkari@kolumbus.fi, on Wed, Jan 26, 2005 at 07:51:57AM +0900:
> Really, I just want those methods! But, there is no way to get them in
> my class other than copying, or convincing the maintainer to cut his
> class into pieces for me. Too bad.

I can see your point: however, a circumstance like this is somewhat exceptional.

I don't agree. I suggest it seems exceptional because its impossible.
Looking at the larger world, copy code around is rampant, not
exceptional!

Its like Class being "open" in Ruby. People regularly add methods to
library classes. Its a way of code-sharing, by adding your code to
existing.

The opposite is not possible, where you take code from the library, and
add it to yours.

Usually such is not possible due to method dependencies or missing variables
or whatever. The 'proper' thing to do would be to factor out such common code
and implement a Module (e.g. Enumerable) with the desired functionality. If
you can't factor it out, it means the implementation should remain separate.

Don't know why you decide "usually", you have spent a lot of time
looking at the library src, and the code you copy out mostly needed small
tweaks, the methods couldn't have been rebound to your classes?

The proper thing is to factor the code out, sure, but its not exactly
'proper' to inject methods into the standard library, is it? And yet,
it is so useful.

Sam

Quoteing dblack@wobblini.net, on Wed, Jan 26, 2005 at 09:31:29PM +0900:

Hi --

>Duck typing, essentially, means that, /in a particular context/, a
>given object has all the characteristics of a given type. For example,
>it might be enough for an object to implement and = for it to be
>treated as a Hash in a certain context.

It's not exactly that it's being treated as a Hash -- it's more that,
*like* a Hash, it's being treated as an object that responds to and
=. This is, perhaps, a subtle point, but I think it's key in
getting away from the class-based view. All of the /= objects
converge on the type that can only be described as "the type of
objects that respond to and =". In that sense, Hashes are just
one of infinitely many possible objects that exhibit the behaviors of
that type.

I see your point.

However, if it responds to = in a way that is NOT like a Hash responds
to those methods, it aint ducky type like a Hash.

Cheers,
Sam

···

On Wed, 26 Jan 2005, E S wrote:

Hi --

Quoteing dblack@wobblini.net, on Wed, Jan 26, 2005 at 09:31:29PM +0900:

Hi --

Duck typing, essentially, means that, /in a particular context/, a
given object has all the characteristics of a given type. For example,
it might be enough for an object to implement and = for it to be
treated as a Hash in a certain context.

It's not exactly that it's being treated as a Hash -- it's more that,
*like* a Hash, it's being treated as an object that responds to and
=. This is, perhaps, a subtle point, but I think it's key in
getting away from the class-based view. All of the /= objects
converge on the type that can only be described as "the type of
objects that respond to and =". In that sense, Hashes are just
one of infinitely many possible objects that exhibit the behaviors of
that type.

I see your point.

However, if it responds to = in a way that is NOT like a Hash responds
to those methods, it aint ducky type like a Hash.

Do you mean how many arguments it takes? Beyond that, one object's
behavior on being sent the = message doesn't have to resemble
another object's, from the point of view of type. The main thing is
that they can both handle the message (including arguments).

Actually this is an area where people have pointed to a potential
limitation or even pitfall of duck typing: namely, coincidence of
method name where there really is no common ground -- something like:

   dog.bark # ask dog object to bark
   tree.bark # retrive bark attribute of tree

On the other hand, I'm not sure there have been any real-world reports
of things like this causing problems. And a lot of duck typing ends
up dealing with cases where at least loose conventional expectations
apply (like and = being index-ish, and << being append-ish).

David

···

On Wed, 26 Jan 2005, Sam Roberts wrote:

On Wed, 26 Jan 2005, E S wrote:

--
David A. Black
dblack@wobblini.net

Quoteing dblack@wobblini.net, on Wed, Jan 26, 2005 at 11:22:33PM +0900:

>>>Duck typing, essentially, means that, /in a particular context/, a
>>>given object has all the characteristics of a given type. For example,
>>>it might be enough for an object to implement and = for it to be
>>>treated as a Hash in a certain context.
>>
>>It's not exactly that it's being treated as a Hash -- it's more that,
>>*like* a Hash, it's being treated as an object that responds to and
>>=. This is, perhaps, a subtle point, but I think it's key in
>>getting away from the class-based view. All of the /= objects
>>converge on the type that can only be described as "the type of
>>objects that respond to and =". In that sense, Hashes are just
>>one of infinitely many possible objects that exhibit the behaviors of
>>that type.
>
>I see your point.
>
>However, if it responds to = in a way that is NOT like a Hash responds
>to those methods, it aint ducky type like a Hash.

Do you mean how many arguments it takes? Beyond that, one object's
behavior on being sent the = message doesn't have to resemble
another object's, from the point of view of type. The main thing is
that they can both handle the message (including arguments).

and what they do with those args.

Actually this is an area where people have pointed to a potential
limitation or even pitfall of duck typing: namely, coincidence of
method name where there really is no common ground -- something like:

  dog.bark # ask dog object to bark
  tree.bark # retrive bark attribute of tree

On the other hand, I'm not sure there have been any real-world reports
of things like this causing problems.

How about #each? Almost every class has one - I'm not sure that thinking
of "the type of objects that respond to #each" will get you very far in
Ruby!

And a lot of duck typing ends up dealing with cases where at least
loose conventional expectations apply (like and = being
index-ish, and << being append-ish).

with Bignum, Array, and Hash are all indexish, and calling an API
expecting a Hash of values (String => value) as an arg with a Bignum
will not work well! On the other hand, a DB table that maps String to
values might very well work, because it's is more like a Hash, and
less like a Bignum.

So, I guess I don't understand your point. Knowing a class responds to a
method, particularly the common method names like #each and # doesn't
seem to tell you much about the interface, really. Interface is more
than syntax, the semantics are pretty important, IMHO.

Cheers,
Sam

p.s. Even Continuation has ! It's the same as #call(). I just learned
that now.