Hi --
On Sat, 3 Mar 2007, Rick DeNatale wrote:
I'm not sure how that detaches it from the object, though, since
variables are going to contain references to objects and messages are
sent to objects rather than variables. Do you mean in terms of
documentation?
First of all let me reiterate that this is my personal perspective,
based on 20+ years of using a variety of dynamic OO languages.
I'm trying to say that the code which uses objects in general sees
them through variables. This isn't always evident, and it's muddied
because so often the same code which uses a variable initializes it,
but in the case of parameters, or the results of expressions based on
parameters that code has less control over what the objects referenced
by variables really are.
One way to think about what I'm saying is to think of the programmer
like a playwright who writes a script in terms of dramatis personae or
roles, without necessarily knowing or caring which actors will
ultimately play those roles.
Many years ago I wrote a paper called "Types from the Client's
Viewpoint" which talked about this, A PDF of this is available on my
blog website at
http://talklikeaduck.denhaven2.com/files/TypesFromTheClientsViewpoint.PDF
I've been struggling for many years about how to describe this without
getting wrapped up in what is really a paradigm shift which confounds
discussion since terms like type have subtly different meanings. That
paper is an early attempt, but it provides on such attempt. Another
glimmer of what I'm trying to say and it's evolution can be seen in my
mini-memoir
http://talklikeaduck.denhaven2.com/articles/2006/07/29/about-me
Because of this paradigm shift problem, I sometimes use the term role
instead of type when talking about variables in an analogy the
playwright metaphor.
One of the key aspects of the paradigm shift is that in a dynamically
typed system a strong wall of encapsulation can be erected between the
user of an object and the implementation of that object.
Traditionally types in programming languages are really names or
calculi for describing how a string of bits are to be interpreted by a
program using those bits. In a language like Ruby or Smalltalk, all
the bit interpretation gets done by the object itself, so the user of
the object doesn't or shouldn't care about the implementation of the
object. This is why those of us in the dynamic duck typing camp are
so adverse to class checking, since the class of an object is an
implementation matter.
This encapsulation wall at the interface between object and user is
what I consider the hallmark of object centered softwre design This
is what Alan Kay seemed to have in mind when he coined the term
"Object Oriented Programming." Unfortunately, Peter Wegner came along
later and coopted the term to require classes and inheritance, both of
which might be useful implementation techniques but are non-essential
to my mind.
And the fact that classes and inheritance are implementation
techniques is another thing which makes those familiar with C++ like
languages have difficulties in getting duck typing. Since
traditionally types are a way of describing an implementation rather
than more abstract usage requirements, classes, inheritance, and the
concept of a strong type all get wrapped so tightly together that they
can't separate them.
I don't think duck typing has ever been about a checklist of common
data structures or types (queue, stack, etc.), but more about just
sending messages to objects without a lot of pre-message checking as
to their class and ancestry and so forth.
I wasn't saying that all of the roles fall into one of these
checklists, but that these and their variations of them are common
roles, just like there are common roles like ingenue, jilted lover,
thug etc. Other roles are more inventive and complex, like the
ex-astronaut rancher building a missile in his barn, or an autistic
savant called rain man.
To me, the ultimate duck
typing idiom is:
def m(x)
x << "string"
end
There's no checking, no probing the object -- you just ask it to do
something, and deal with what happens. In the end, that's *always*
how things are when writing Ruby. I've always seen "duck typing" as
just a kind of embrace of the conditions under which every single line
of Ruby is code is written anyway.
Yes, and this is completely compatible with what I'm saying. Think
again about the play, the playwright writes the play, actors are cast,
and the production of the play is developed through rehearsal
(testing), debugging (re-writes) and sometimes re-casting. Later
productions can use different casts, possibly with additional
adaptation.
All these nouns sound more like classes than types. Actually I don't
think the type of a Ruby object can ever be named. It's circular: the
type of an object is... the type of objects that are of this object's
type
As soon as it gets noun-like it starts getting class-bound
again.
Which nouns? hammer, wrench, rock, yes you can think of these as
classes (but more on this in a bit). But mass?
Now you are right that it's often hard to name a role, but never say
never. The name might stand for a complex type like Romeo, Othello,
or Tony Soprano, or it might be a noun phrase like "mass which can be
conveniently accelerated...".
The point though is that naming it isn't enough. Again in an analogy
with writing a play, the playwright's conception of the role doesn't
usually spring full-blown when the character's name gets written down,
but evolves as the play is written and the character interacts with
other characters in the play, and then further evolves as the director
begins to interpret the play.
Imagine Shakespeare writing Romeo and Juliet in C++, he'd have to
pre-declare all the players, and come up with strong types closely
bound to the implementation of the actors, before he wrote a line of
dialog.
Ay there's the rub!