--- "David A. Black said:
Hi --
=20
On Wed, 17 Aug 2005, Lyndon Samson wrote:
=20
hostility towards.
=20
Duck typing co-exists peacefully with the existence of
classes -- or
at least it can. The biggest problem I've seen over the
years in the
matter of understanding Ruby's particular class/prototype
blend is the
"class =3D=3D type" fallacy.
Using the term "type" by itself instead of something else helps
perpetuate this fallacy. Object#type is a synonym of
Object#class.
There are two common consequences
of this
misunderstanding. First, it leads to the creation of new
ways of
referring to type (like "duck type", which is redundant and
superfluous).
Your definition of "type" is quite different from the
definition I gave of "duck type". Your definition of the
"type" of an object is the "sum of all of its capabilities" -
i.e. ALL of the methods it responds to. I think that
definition is about as relevant to ruby and duck-typing as
class is. This definition of "type" is close to a java
"interface", but is more restrictive because it represents the
entire behavior of an object where an interface may be just a
subset. From your definition of "type", an object only has
one "type" for any given state of that object.
The definition I gave of "duck type" allows an object to have
many "duck types" at a time. It all depends on who is using
the object. Each usage of an object may have a different view
of what the "duck type" is. My definition of "duck type"
really refers to the usage of an object not the object itself.=20
The most common usage would be as a method argument, but it
could also be applied to variables, using return values from
methods, etc. I think the broadest definition I could give
would be that a "duck type" of a given usage of an object is
described by what capabilities are used of that object in that
context. This includes what methods that object needs to
respond to, the arity of those methods, the "duck type" of the
arguments for those methods, and the "duck type" of what is
returned from those methods.
Take a look at the original definition of duck-typing given by
Dave Thomas. Here is the example he gave:
| When I write
|
| fred << "dog"
|
| in Ruby, I don't care whether fred is a String, a File, or an
| Array
In this context, the "duck type" of fred is something that
reponds to <<(aString).
By your definition of "type" being "the sum of all of its
capabilities", you'd have to pick what "type" fred is -
String-like, File-like, or Array-like. If you said that fred
was something File/IO-like you could use an IO, File, or
StringIO for fred, but not a String or Array because they don't
have the same capabilities.
The downside of typing your arguments using this "duck type"
definition is that you have to pick what methods you want to
use up front and document what you are using (or may use). If
you later want to change the implementation to use other
methods, you'll need to change the docs and possibly break
callers using objects under the original duck-type. With the
"type" definition you have, this downside doesn't exist. A
method has much more freedom of choice. For example, in the
above, you could change it to fred.write("dog") later down the
road if you limited fred to be anything IO-like.
So, if you want to give maximum freedom of choice to the
caller, you should describe your arguments with duck-types and
if you want to give maximum freedom of choice to the method
implementor, you should describe your arguments with David's
definition of "type".
Second, and sort of the opposite, it leads to
the
impression that there's something arcane, wizardly, "evil",
and/or
just plain bad about modifying objects during runtime so that
their
type is not the same as the type they started out with.
The biggest problem I have with being able to add/remove/modify
methods of an object (using a meta class or directly in the
object's class) is the future of optimization in Ruby. Adding
methods may not cause too much of an issue, but modifying them
sure could. For example:
i =3D 0
i +=3D 1
In this case, Ruby could recognize that i is always a Fixnum
(or a Bignum depending on how smart it is). If it knew exactly
what "+" was for a Fixnum, it would be able to in-line that C
call (in this hypothetical Ruby compiler). Unfortunately, "+"
could be anything since it can change at run-time.
To me, this is an extreme case of methods that mutate the
object. If one thinks #reverse! is bad compared to #reverse
(which I don't) because it mutates the object rather than
returning a new one, being able to modify the methods of an
object (or objects if for a whole class) should seem hideous.=20
Personally, I don't think adding methods are too bad, but being
able to remove or modify methods doesn't seem like a good idea
or serve much use. I'd rather see a new object be created that
have these methods removed/modified instead.=20
=09
____________________________________________________
Start your day with Yahoo! - make it your home page=20
http://www.yahoo.com/r/hs=20
=20