Hi --

On Fri, 8 Aug 2003, Mills Thomas (app1tam) wrote:

> > -----Original Message-----
> > From: dblack / superlink.net [mailto:dblack / superlink.net]
> > Sent: Thursday, August 07, 2003 6:41 PM
> > To: ruby-talk / ruby-lang.org
> > Subject: Re: Ducktype, right?
> > > This is sort of like having a discovered mixin.  Neat.
> >                               ^^^^^^^^^^^^^^^^^^
> >
> > Intriguing phrase.  What do you mean exactly? :-)
> >
>
> >From my days as a LISP programmer, we could create objects at will just by
> mixing in (thus, mixin) named capabilities.  This would be done explicitly.
> Example:
>
> ;;;in CLOS/LISP
> (defclass my-animal-robot (basic-robot
>                            house-cleaner-mixin
>                            duck-mixin)
>   (... now my robot-duck can clean the house ...))
> ;;;;
>
> So it's sort of like multiple inheritance, but when I was doing LISP it was
> much looser than 'inheritance'.  You just tossed it in there.  But still, it
> was defined previously.

As you probably know, Ruby also has mixins:

    def talk
      puts "quack"
    end
  end

  class A
    include M         # mixin
  end

  A.new.talk   # => quack

and you can even extend the capabilities of a single object this
way:

  module MM
    def walk
      puts "waddling..."
    end
  end

  duck = A.new
  duck.extend(MM)
  duck.walk       # => waddling

  A.new.walk      # unknown method error (*this* A object can't walk)

> So, to answer your question.  I'm just saying it's a neat idea that I could
> check ANY object to see if (discover) that the object has this capability
> (kindof like a mixin) solely based on it's operations, as opposed to its
> having been formally defined that way.
>
> ### in Ruby
> yourRobot.quack if ducktype(yourRobot, duckness)
> duckHerder.buy(myRobot) if ducktype(myRobot, duckness)

(I'm not sure I'd file the second example under "duck typing"
(since it's argument-checking rather than object capability
checking), but you could probably come up with a method name
that was a superset of both :-)

> ###

You could also just do:

  your_robot.quack if your_robot.respond.to?("quack")

(i.e., an unmediated test of the object's capabilities at exactly the
moment when you want those capabilities), or, if you have a lot of
nanoseconds to spare:

  begin
    your_robot.quack
  rescue NameError
    your_robot.bark
  # etc.
  end

The thing that bothers me about the explicit respond_to? test is the need
to type everything twice.  But I've never come up with a way around that,
except the exception-raising one which is a lot slower.  It also might
catch the wrong exception... for instance if you have:

  def quack
    100.blah     # no such method
  end


David

-- 
David Alan Black
home: dblack / superlink.net
work: blackdav / shu.edu
Web:  http://pirate.shu.edu/~blackdav