[ANN] Ducktator - A Duck Type Validator

Devin, I don't want to stress this but you may be underestimating the value of clear terms a bit. IMHO we should at least /try/ to get a common understanding of some core concepts so we talk past each other as little as possible. So, yes I think these discussions are necessary from time to time. Sometimes the line between persistence and zealotry is blurred. And unfortunately sometimes these discussions then take such an unfriendly turn as this thread did.

Kind regards

  robert

···

On 21.09.2006 05:20, Devin Mullins wrote:

Devin Mullins wrote:

Do we need separate terms to describe the different meanings Eric enumerated (and potentially others)? Well, no, but it'd be helpful. I'll start.

Oh, and lastly:

Can we expect everybody in the world to conform to a standard set of vocabulary, should we come to agree on one? HELL NO!

} Austin Ziegler wrote:

···

On Thu, Sep 21, 2006 at 03:39:12AM +0900, Joel VanderWerf wrote:
} >On 9/20/06, Ola Bini <ola.bini@ki.se> wrote:
} >>The problem with "just use it", is that you will have no control over
} >>error handling in this case.
} >
} >This is demonstrably untrue. Duck typing is not about validation. It's
} >about trusting your callers to do the right thing -- and then doing
} >the right thing when they don't.
}
} To extend Austin's point a little: In ruby, it really has to be this
} way. What if an object responds to a message by way of method_missing?
} There's no easy way to validate that.

Actually, it is the developer's responsibility to override respond_to? when
overriding method_missing. To do one and not the other is just sloppy.

} vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407
--Greg

Devin Mullins wrote:
> Do we need separate terms
> to describe the different meanings Eric enumerated (and potentially
> others)? Well, no, but it'd be helpful. I'll start.
Oh, and lastly:

Can we expect everybody in the world to conform to a standard set of
vocabulary, should we come to agree on one? HELL NO!

Hmm that sounds strange to me:
Do you think we missunderstand each other on purpose?
Even if we were all native English speakers the limitations of the written
language will kick in.
No I have to say that I find this a very interesting and didactic thread,
look e.g. at your statement
"Boy, we really love to argue about semantics, don't we?"
it struck me, for meself it is one of the main purposes of the ML, for
yeself it seems unnecessary, I guess we do not interpret the sentence in the
same way, and I assume that we do not do this on purpose.
Hopefully I got my point accross - which is funny because the point I want
to get accross (is this English BTW?) is that is almost impossible to get
the point accross.

Cheers
Robert

That is all.

···

On 9/21/06, Devin Mullins <twifkak@comcast.net> wrote:

Devin

--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein

Austin Ziegler wrote:

> No, you better not. If I use #<<, then I can "write" to a String, a
> StringIO, an IO (socket, file, etc.), or an Array. Checking for #write
> limits you to (mostly) actual IO objects.

Then you'd be asking if the object _acts like_ (quacks like) an
enumerable, would you not? Why wrap that in a begin....rescue clause
and only spot it after the fact when you can catch it ahead of time?
Certainly it doesn't violate duck-typing to ask what an object acts
like (which is what imposing conditions on an object would be doing)?!

Because with duck typing, you break exactly at the point where an
object doesn't behave like it's supposed to, not before or (worse)
later.

···

On 9/20/06, MonkeeSage <MonkeeSage@gmail.com> wrote:

Regards,
Jordan

--
- Simen

As Simen Edvardsen says, preconditions or exception handling can
change the location of the error reported so that you're not sure
whether you're dealing with the error at the right location or not.
There are good reasons for having both, but they're *additional*
techniques that can be used.

But I didn't say anything about wrapping #<< calls in a
begin/rescue/end clause. I didn't ask whether the object acts like an
enumerable (because, in fact, I don't care if it's enumerable or not).
I just told it #<< with some arguments. If it doesn't actually
understand #<<, it's going to break -- and that means someone gave me
an object that doesn't work like it is supposed to, or I transformed
the object in a negative way.

When one is duck typing, one is applying a concept, not formalizing an
interface. Ducktator is many things, but it isn't an "implementation
of duck-typing". By definition, there can be no implementation of a
duck type validator -- it's not something that is able to be
statically defined at any point.

-austin

···

On 9/20/06, MonkeeSage <MonkeeSage@gmail.com> wrote:

Austin Ziegler wrote:
> No, you better not. If I use #<<, then I can "write" to a String, a
> StringIO, an IO (socket, file, etc.), or an Array. Checking for #write
> limits you to (mostly) actual IO objects.
Then you'd be asking if the object _acts like_ (quacks like) an
enumerable, would you not? Why wrap that in a begin....rescue clause
and only spot it after the fact when you can catch it ahead of time?
Certainly it doesn't violate duck-typing to ask what an object acts
like (which is what imposing conditions on an object would be doing)?!

--
Austin Ziegler * halostatue@gmail.com * http://www.halostatue.ca/
               * austin@halostatue.ca * You are in a maze of twisty little passages, all alike. // halo • statue
               * austin@zieglers.ca

Leslie Viljoen wrote:

Austin Ziegler wrote:
>> The problem with "just use it", is that you will have no control over
>> error handling in this case.
>
> This is demonstrably untrue. Duck typing is not about validation. It's
> about trusting your callers to do the right thing -- and then doing
> the right thing when they don't.

To extend Austin's point a little: In ruby, it really has to be this
way. What if an object responds to a message by way of method_missing?
There's no easy way to validate that.

Of course the whole scheme really relies on the library writer to
provide very good documentation - they have to (re)discover and
document every method call they perform on every object passed to
them. Unless they fall back to the old ways and say "this method
expects a string, and all that that implies". Which doesn't help the
user of the library much because say they want to pass in something
else that works a little like a string, but does not exhaustively
support every method the String class supports? They have to read the
library source and discover and document every method call on the
object...

Maybe it has to be a String - maybe not. If not, you can use a probe

class Probe
   def method_missing(*a,&b)
     p [self, *a]
   end
end

Kind regards

  robert

···

On 9/20/06, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:

> On 9/20/06, Ola Bini <ola.bini@ki.se> wrote:

Devin Mullins wrote:

For backwards compatibility with the great majority, "duck typing" will
mean "just calling methods on an object, without doing any validation on
the behavior of that object."*

The great majority of whom? If you mean rubyists, perhaps you're right
(though I don't know). If you mean programmers, language designers and
computer scientists in general, I think you're wrong.

"Duck typing" is not something that you _do_, and is not even _how you
do something_; it is a method of relating objects -- a sort of "type
system" ("type" in the generic sense not the C-type sense; i.e., "A
type indicates a set of values that have the same sort of generic
meaning or intended purpose (although some types, such as abstract
types and function types, might not get represented as values in the
running computer program)." [1]).

In the terms of category theory: "Instead of focusing merely on the
individual objects (groups) possessing a given structure [...] category
theory emphasizes the morphisms - the structure-preserving processes
- between these objects. [...] A category is itself a type of
mathematical structure, so we can look for 'processes' which preserve
this structure in some sense. Such a process is called a functor. It
associates to every object of one category an object of another
category; and to every morphism in the first category a morphism in the
second." [2]

So "In computer science, duck typing is a term for dynamic typing
typical of some programming languages, such as Smalltalk or Visual
FoxPro, where a variable's value itself determines what the variable
can do. Thus an object having all the methods described in an interface
can be made to implement that interface dynamically at runtime, even if
the object's class does not include the interface in its implements
clause. It also implies that an object is interchangeable with any
other object that implements the same interface, regardless of whether
the objects have a related inheritance hierarchy." [3]

The python glossary defines the expression similarly: "Pythonic
programming style that determines an object's type by inspection of its
method or attribute signature rather than by explicit relationship to
some type object ("If it looks like a duck and quacks like a duck, it
must be a duck.") By emphasizing interfaces rather than specific types,
well-designed code improves its flexibility by allowing polymorphic
substitution. Duck-typing avoids tests using type() or isinstance().
Instead, it typically employs hasattr() tests or [Easier to ask for
forgiveness than permission] programming" [4] Note also that python
calls the method of programming which you call "duck typing" -- "just
calling methods on an object, without doing any validation on the
behavior of that object" -- "Easier to ask for forgiveness than
permission"

Structural type systems, as found in dialects of ML and other
languages, are very similar to duck typing. "In structural typing, two
objects or terms are considered to have compatible types if the types
have identical structure." [5] This "structure" is often referred to as
the "shape" or "signature" of the object / type.

Now I don't know if Dave Thomas used the expression "duck typing"
differently than others generally do, leading to it having a different
nuance in the ruby community; or if perhaps the community didn't
understand Mr. Thomas; or some combination of the two (or, as a third
alternative, the community doesn't generally have that notion of "duck
typing"). But generally speaking "duck typing" does not require or even
imply any specific programming approach (including the approach where
one simply expects / trusts that one object will act like / has the
same (or pragmatically similar) signature as another). If it did, then
(in many cases) when you write begin...rescue, you'd be violating "duck
typing", because you're no longer trusting the object, but are imposing
a condition on it -- you're just doing it "after the fact", so to
speak: try it -> failed -> do something else. This is no different in
concept from ask about it -> failed -> do something else, it's just a
different implementation.

So, in colloquial terms, I see no reason why "ask if it walks like a
duck before you believe its a duck" should be a violation of "duck
typing" any more than "expect it to walk like a duck but don't believe
its a duck if it doesn't".

Ps. I also agree with Matz. I see no reason for zealotry. If I'm wrong,
that's OK; I've been wrong plenty of times before and will be wrong
again. No need to get upset over it.

[1] Type system - Wikipedia
[2] Category theory - Wikipedia
[3] Duck typing - Wikipedia
[4] http://docs.python.org/tut/node18.html#l2h-46
[5] Structural type system - Wikipedia

Regards,
Jordan

Eero Saynatkari wrote:

Devin Mullins wrote:
> Devin Mullins wrote:
>> Do we need separate terms
>> to describe the different meanings Eric enumerated (and potentially
>> others)? Well, no, but it'd be helpful. I'll start.
> Oh, and lastly:
>
> Can we expect everybody in the world to conform to a standard set of
> vocabulary, should we come to agree on one?

You know, it would really help :slight_smile:

remember the eigenclass / metaclass / singleton / virtual / adhoc /
whatever class discussion?

Here is a shot at giving some terms without trying to judge what is best:

pure duck typing : just use the object as-is. Don't do anything that will
check it to see if it has specific capabilities, ancestors, class, etc.

virtual duck typing : the functionality is equivalent to pure duck typing,
but for whatever reason #respond_to?, #class, etc has been used. This could
be to check capabilities sooner rather than waiting for a method missing, or
it could be done for performance reasons by special casing certain classes (
i.e. builtins).

duck type : a description of what capabilities an object needs in the
context of pure or virtual duck typing. This description could be quite
recursive going into the duck type of the arguments passed to the methods
and the return values of the methods.

complete type : a description of all of the capabilities of an object.

multi-method : a method that checks the capabilities or class of an argument
to choose between different functionality. Other terms to go along with
this: multi-typing?, multi-type?.

class conversion : using a method (i.e. #to_*) to convert an object to a
specific class. If the result of this conversion must be a specific class
(or descendent of) and not just have a certain "duck type", it probably
should not be considered duck-typed.

···

On 9/21/06, Robert Klemme <shortcutter@googlemail.com> wrote:

On 21.09.2006 05:20, Devin Mullins wrote:
> Devin Mullins wrote:
>> Do we need separate terms to describe the different meanings Eric
>> enumerated (and potentially others)? Well, no, but it'd be helpful.
>> I'll start.
> Oh, and lastly:
>
> Can we expect everybody in the world to conform to a standard set of
> vocabulary, should we come to agree on one? HELL NO!

Devin, I don't want to stress this but you may be underestimating the
value of clear terms a bit. IMHO we should at least /try/ to get a
common understanding of some core concepts so we talk past each other as
little as possible. So, yes I think these discussions are necessary
from time to time. Sometimes the line between persistence and zealotry
is blurred. And unfortunately sometimes these discussions then take
such an unfriendly turn as this thread did.

Maybe. I did point out that in my early days of programming Ruby, I
would implement one without the other. But simply doing a #respond_to?
check doesn't help you with arity checking, which matters as much as
the presence of the method itself.

-austin

···

On 9/21/06, Gregory Seidman <gsslist+ruby@anthropohedron.net> wrote:

Actually, it is the developer's responsibility to override respond_to? when
overriding method_missing. To do one and not the other is just sloppy.

--
Austin Ziegler * halostatue@gmail.com * http://www.halostatue.ca/
               * austin@halostatue.ca * You are in a maze of twisty little passages, all alike. // halo • statue
               * austin@zieglers.ca

Gregory Seidman wrote:

} To extend Austin's point a little: In ruby, it really has to be this } way. What if an object responds to a message by way of method_missing? } There's no easy way to validate that.

Actually, it is the developer's responsibility to override respond_to? when
overriding method_missing. To do one and not the other is just sloppy.

An interesting point, and tentatively it seems reasonable (though there
are probably exceptions).

Along those lines, you might also want to add the method to the
instance_methods list so that reflection works as expected.

One interesting variation on the use of method_missing that I've used
once or twice is: When method_missing is called, *create* the method
and make it do the "right thing." Then respond_to? and reflection
will henceforth work as expected.

Hal

···

On Thu, Sep 21, 2006 at 03:39:12AM +0900, Joel VanderWerf wrote:

I've put my 10 cents about this thread in my blog.

http://talklikeaduck.denhaven2.com/articles/2006/09/21/schrödingers-duck

···

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

No I have to say that I find this a very interesting and didactic thread,
look e.g. at your statement
"Boy, we really love to argue about semantics, don't we?"
it struck me, for meself it is one of the main purposes of the ML, for
yeself it seems unnecessary, I guess we do not interpret the sentence in the
same way, and I assume that we do not do this on purpose.

I've always been bemused when someone says, "It's just a question of
semantics" to cut off a discussion. Doesn't semantics mean "meaning"
and if so, it seems to me that that's more interesting to discuss
than, say, syntax.

Hopefully I got my point accross - which is funny because the point I want
to get accross (is this English BTW?)

Yes, except for the spelling of across.

But then evun nativ Englush speekers oftin mispel Englush werds! <G>

is that is almost impossible to get
the point accross.

Amen!

···

On 9/22/06, Robert Dober <robert.dober@gmail.com> wrote:
--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Well,

I don't want to continue this discussion in this venue, since the discussion isn't really about what I meant with the project and such. Duck typing also seems to be a very loaded (might I say religious) word for people in the Ruby-community.

I've written a small blog post about the issue, but I can't guarantee that we will all be friends, even after you read it:

Cheers

···

--
  Ola Bini (http://ola-bini.blogspot.com)
  JvYAML, RbYAML, JRuby and Jatha contributor
  System Developer, Karolinska Institutet (http://www.ki.se)
  OLogix Consulting (http://www.ologix.com)

  "Yields falsehood when quined" yields falsehood when quined.

Ah thank-you, that's great. But it would not work unless every
execution path within the method receiving the object was executed:

class Probe
    def method_missing(*a,&b)
          p [self, *a]
    end
end

def testProbe(probe)
  if probe>5
    puts probe.destroy
  else
    puts probe.accept
  end
end

p = Probe.new
testProbe(p)

···

On 9/20/06, Robert Klemme <shortcutter@googlemail.com> wrote:

Leslie Viljoen wrote:
> On 9/20/06, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:
>> Austin Ziegler wrote:
>> > On 9/20/06, Ola Bini <ola.bini@ki.se> wrote:
>> >> The problem with "just use it", is that you will have no control over
>> >> error handling in this case.
>> >
>> > This is demonstrably untrue. Duck typing is not about validation. It's
>> > about trusting your callers to do the right thing -- and then doing
>> > the right thing when they don't.
>>
>> To extend Austin's point a little: In ruby, it really has to be this
>> way. What if an object responds to a message by way of method_missing?
>> There's no easy way to validate that.
>
> Of course the whole scheme really relies on the library writer to
> provide very good documentation - they have to (re)discover and
> document every method call they perform on every object passed to
> them. Unless they fall back to the old ways and say "this method
> expects a string, and all that that implies". Which doesn't help the
> user of the library much because say they want to pass in something
> else that works a little like a string, but does not exhaustively
> support every method the String class supports? They have to read the
> library source and discover and document every method call on the
> object...

Maybe it has to be a String - maybe not. If not, you can use a probe

class Probe
   def method_missing(*a,&b)
     p [self, *a]
   end
end

---------------------
lesliev@derik:~$ ./testProbes.rb
[#<Probe:0xb7cbaa70>, :>, 5]
[#<Probe:0xb7cbaa70>, :accept]
nil

...so is there some magic that could overcome that limitation?

MonkeeSage wrote:

[snippage]

Overall I don't disagree with you. :wink:

Now I don't know if Dave Thomas used the expression "duck typing"
differently than others generally do, leading to it having a different
nuance in the ruby community; or if perhaps the community didn't
understand Mr. Thomas; or some combination of the two (or, as a third
alternative, the community doesn't generally have that notion of "duck
typing").

One thing I'm wondering is: Is there any evidence that this term
originated *other than* with Dave Thomas?

Certainly it's known outside the Ruby community now, but didn't the
term originate *within* the community?

Not that it matters really. AFAIK Dave himself doesn't claim to have
coined the term. And I take it for granted that the concept is older
than the term.

So, in colloquial terms, I see no reason why "ask if it walks like a
duck before you believe its a duck" should be a violation of "duck
typing" any more than "expect it to walk like a duck but don't believe
its a duck if it doesn't".

I *think* that most people (me, anyway) perceive that checking type
is antithetical to the spirit of duck typing.

I'm not adamant about it. And I do perform this kind of checking
sometimes (gasp!).

Cheers,
Hal

MonkeeSage wrote:
> I trust everything that Wikipedia says.
(Well, I paraphrased that a bit...)

You, there's a way of thinking about the phrase "duck typing" that'll help explain that it's really a description of a programming strategy.* Intepret "duck" as a verb. When you use "duck typing," as a programmer, you "duck" the programming language's definition of "typing." (Class, in Ruby's case) Wait, that sounds familiar... did I read that somewhere?

Just a thought.

Devin
(I was kidding, Jordan. Just messing wit j00. I lack knowledge of category theory.)

* Scanning over chapter 23 of the PickAxe seems to confirm that that was the intention -- pages 370-1 use the phrases "duck typing philosophy" and "this style of laissez-faire programming," though, granted, the book isn't consistent. Hey, the phrase is out there. It doesn't seem to have a canonical definition. It's an ad hoc term. Treat it as such, I say.

For posterity, I just want to say that I love all you guys (i.e., all
my fellow rubyists). I think of us like a big family. Even though we
may have some scuffles from time to time, at the end of the day, blood
is thicker than water. The ruby community is one of the best I've ever
come across, and I don't want newbies to get the impression that we're
all fractured and at each other's throats all day long. I don't think
that is true at all. So I just wanted to say explicitly that all of you
are awsome (whether we agree or not)! In the words of Bob Marley, "one
love"!

</endSappyTransmission>

Regards,
Jordan

Austin Ziegler wrote:

But simply doing a #respond_to?
check doesn't help you with arity checking, which matters as much as
the presence of the method itself.

Very true. In the same way (as others have mentioned), method_missing
dispatching can cause some serious flaws in signature validation. And
method_missing with variable arity is even worse, heh!

Regards,
Jordan

that's pretty interesting austin - i haven't considered that before. i'm
already in the habit of checking arity on blocks and calling them with the
'correct' number of paramters - i wonder if a simple design pattern might help
with that situation, for example:

     harp:~ > cat a.rb

···

On Fri, 22 Sep 2006, Austin Ziegler wrote:

On 9/21/06, Gregory Seidman <gsslist+ruby@anthropohedron.net> wrote:

Actually, it is the developer's responsibility to override respond_to? when
overriding method_missing. To do one and not the other is just sloppy.

Maybe. I did point out that in my early days of programming Ruby, I
would implement one without the other. But simply doing a #respond_to?
check doesn't help you with arity checking, which matters as much as
the presence of the method itself.

-austin

     #
     # an open-struct class, with a demo impl of method_missing/respond_to pair
     #
     class OpenStruct
       def initialize h = {}
         (@h = {}).update h
       end

       def method_missing m, *a, &b
         key = m.to_s
         w = key.sub! %r/=$/, ''
         if w
           val = a.shift || b.call
           @h[key] = val
         else
           @h[key]
         end
       end

       def respond_to? m
         if super
           method m
         else
           key = m.to_s
           w = key.sub! %r/=$/, ''
           w ? lambda{|k,v|} : lambda{|k|}
         end
       end
     end

     os = OpenStruct.new 'key' => 'val', 'a' => 'b'
     os.x = 'y'

     if how = os.respond_to?('x')
       puts "'x' artiy : #{ how.arity }"
     end

     if how = os.respond_to?('x=')
       puts "'x=' artiy : #{ how.arity }"
     end

     if how = os.respond_to?('to_s')
       puts "'to_s' artiy : #{ how.arity }"
     end

     if how = os.respond_to?('send')
       puts "'send' artiy : #{ how.arity }"
     end

     harp:~ > ruby a.rb
     'x' artiy : 1
     'x=' artiy : 2
     'to_s' artiy : 0
     'send' artiy : -1

so, rather than returning a simple bool from 'respond_to?' we return an object
describing __how__ it responds - either a method object or a lambda, either of
which can be used to determin arity.

just a thought...

cheers.

-a
--
in order to be effective truth must penetrate like an arrow - and that is
likely to hurt. -- wei wu wei