From: "David A. Black" Date: 2005-08-18T04:01:19+09:00 Subject: Re: Prototype-based / Ruby question Hi -- On Thu, 18 Aug 2005, Eric Mahurin wrote: > --- "David A. Black" wrote: > >> 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 == type" fallacy. > > Using the term "type" by itself instead of something else helps > perpetuate this fallacy. Object#type is a synonym of > Object#class. Yes, but that use is deprecated. The explanation given by Matz in the past, as I recall, is that he chose to add the synonym "type" because, at the time, there were problems parsing "class" as a non-keyword, even in method-call position. It's unfortunate that that happened, because it's certainly fanned the flames of the misunderstanding, but it was for understandable technical reasons and hopefully it will be resolved so that "type" can disappear. >> 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. I would start with your statement and "divide by duck" :-) An object's type allows the object to do many things at a time, and be addressed in many ways. I don't feel the need to have a label for the subsets. Just ask the object. (I guess you could call a subset of a type, too, a type. There's no type police. As long as the object does what you claim for its type, that's its type.) > 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. > 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. On the contrary: I *don't* have to pick or describe or find synonyms for what it is. That's the point: the type is what's there. I don't even have to name it. > 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. No, not at all: you're missing the (intentional) circularity -- even tautology -- of my account of "type". "String-like" is not a Ruby type. It may be a partial description of a type -- and it may be a convenient or expedient shorthand for labeling an object's capabilities -- but it is not a type. An object could be "String-like", and also be other things. String-like plus those other things would, essentially, be the object's type. This is circular because it means that the type of object x is "the type which is the type of objects whose type is that of object x." I never have to say that fred is "String-like" or "Array-like" or "-like". All I have to do is send messages to fred. Neither fred nor the caller has to be constrained by aggregations of behavior into "String" and "Array" and so forth. All that matters is what happens at the moment of the method call. > 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. I personally wouldn't say "anything IO-like" (nor "O-like", though that might be closer :-) but rather: anything that responds to "write". That's *all* that matters. "IO-like" is a secondary concept, built on top of that. Let's say someone said: "no, it's not IO-like; I reject that." That person could still send "write" to fred, as much as you can. > 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". Well, I think Ruby grants its own freedoms. I'm not sure what you mean by describing arguments "with" my definition of "type". It sounds very restrictive. I think one should just write programs with objects that do things. That's pretty much how Ruby will see it anyway :-) [...] > 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. It comes in handy for class methods :-) David -- David A. Black dblack@wobblini.net