Schrödinger's Duck

Posted by Rick DeNatale Thu, 21 Sep 2006 15:27:00 GMT

Once again there’s been a recent furore about the meaning of Ducktyping on the ruby-lang mailing list.

A nice young man from Sweden, by the name of Ola Bini, announced “ductator” a ruby-gem which allows type validation of
ruby variables. Now I think that Ola is young based on the photo on his blog site, and I know that he’s nice because only
nice people inhabit ruby-lang.

The real question is just what kind of a type system ductator represents. I’ve taken a brief look at it and it seems to allow one
to describe, via a hash, a list of rules which are applied to a variable’s value at run-time. These rules are things like
a list of methods the value must have, a class which the value must be an instance of, or an instance of a subclass of etc.

The Cat is Dead, Long Live the Cat

In 1935 Erwin Schrödinger, proposed his famous thought experiment, in which a cat, a a radioactive atomic nucleus, and a
cannister of poison gas rigged ot open if the nucleus decayedare placed in a sealed box. The half-life of the neucleus is
such that there is a probability of 1/2 of the nucleus decaying within one hour. Because quantum mechanics states that
until a decay is observed, the nucleus really exists as a superposition of decayed and undecayed states, that the cat is
both dead and alive until the box is open and the observation is made.

Schrödinger’s experiment is really a dramatized version of a similar thought experiment previously published in a paper
co-written by Einstein. Although Einstein intended it as a refutation of the probabilistic nature of quantum mechanics,
the stochastic basis of quantum mechanics has held up over the ensuing seven decades, and such paradoxes have held up.

My point here is that, in a sense, the kind of type checker represented by ducktator. It attempts to observe certain
aspects of an object, and in so doing, has a good chance of killing the duck.

Besides the questions of what duck-typing is or is not, such a set of checks fails under many common usages in ruby.

False Negatives

Relying on responds_to? fails under commonly used Ruby metaprogramming techniques.

It’s very common these days to use method_missing to provide pseudo-methods, or to
create methods on the fly. ActiveRecord and other RubyOnRails componentry makes extensive use
of this technique.

The problem is, of course, that an instance of a class which uses these techniques effectively
gives an invalid response to responds_to?, or may reply false, until the missing
method is invoked, creating the method.

Poking around a bit, I notice that some of the standard library classes, and others liek ActiveRecord, go to some lengths to make responds_to? track with phantom methods implemented via :method_missing, although fixing other reflection methods like :methods and the class method :instance_methods doesn’t seem to be commonly done.
While this is good, it can greatly increase the expense of :responds_to?. ActiveRecord::Base, aliases :responds_to? as responds_to_without_attributes? before redefining :responds_to? for this reason.

In the case of Drb::DrbObject, which is used as the proxy object in Distributed Ruby, handling :respond_to? on behalf of a remote object, requires marshalling a :respond_to? message to the remote object, sending the marshalled message, then reading and unmarshalling the reply. This makes sending :respond_to? to a remote object much more expensive.

And irony of ironies, ductator uses :method_missing to supply phantom methods in it’s
implementation, without implementing a compensating :respond_to?!

False Positives


Even if one accepts the philosopy posited by ductator, using it can get tricky. For example, one might check to see if an object responds_to?(:each), but exactly what :each does and how it interacts with it’s block argument, depends on the class itself. For example, most enumerables yield a single value to the block in :each, but Hash yields both a key and a value.
The block can be written to accomodate this, but it doesn’t have to be. It’s not clear to me how
to either express or check the type of such block arguments. I don’t see a mechanism in
ductator even to check the arity of a proc, and although this could be added, it’s not really
sufficient since it doesn’t express the types required of block arguments.

What’s the Value?


Some folks might find something like ductator to their taste, since it give the impression of making Ruby more like Java or C++. The problem is that in so doing, it makes Ruby less like Ruby.

This kind of type checking seems to be an expensive add-on to the real checking which happens
during program execution. The fact that everything is an object in ruby means that the really
nasty errors in a language like C when you use an integer as a pointer don’t happen. It seems
to me that the best that something like ductator can do is to make a more ‘meaningful’ error
description when something goes wrong, but doing that correctly is harder than it first appears,
and in most cases could be accomplished more efficiently by catching errors with rescue clauses
and changing the error reporting, after the fact, which puts the cost of the error on the
offender rather than taxing everyone with run-time pre-flight tests.

Wrapping up for now


The French word for “duck” is “canard.”

In computer jargon, the word “canard” means a “mistaken and confused belief”. In my humble opinion, the view of duck typing taken by ducktator and its ilk is in this sense really “canard” typing.

Le canard est mort, vive long le canard!

Or translated into English:

The canard is dead, long live the duck!


Trackbacks

Use the following link to trackback from your own site:
http://talklikeaduck.denhaven2.com/trackbacks?article_id=32

Comments

  1. Ryan Daigle 2 days later:
    Come for ruby talk - get quantum mechanics lesson. Loved it.
  2. Robert Dober 2 days later:
    I will try to spell everything right, *this* time. Nice reading, I did not know that respond_to? (never forget Matz is not a native speaker either) was so frequently abused. I will avoid any discussion about ducktyping, early checking or dynamic type checking, but in any case: Exception handling can ( I daresay, shall ) be used. Excellent travail mon ami. Robert
  3. Robin 3 days later:
    Isn't it *Erwin* Schrödinger?
  4. Rick DeNatale 5 days later:
    Robin, right you are! I guess that's what I get for using typo as a blog engine!