From: Eric Mahurin Date: 2005-08-18T06:56:09+09:00 Subject: Re: Prototype-based / Ruby question --- "David A. Black" wrote: > 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. From what you said above, I don't see any debate over how I defined "duck type" (other than the name). I only see you clarifying what you meant by "type". I still don't see a concrete definition of yours, but it sounds like you might mean the same as what I said for "duck type". But, when you say "type" is "the sum of all of its capabilities" and "an object's type can change and evolve during runtime" this says to me your "type" is associated with the object itself and not how the object is used. All that really matters regarding "type" in my opinion is how an object is used. What a particular object's entire capabilities and the fact that they can change over time is orthongonal. I'm not sure why you don't like the term "duck type". It is directly associated with the term "duck typing" and is quite clear in that context. I don't understand the need to talk about/document an abstract "type" beyond the context of "duck typing". Can you think of anything else? > > 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. My point was that if you document your method to take an IO-like object (which I thought was your way - sum of the capabilities of an object), you have the freedom to use any of the IO methods. If initially the method is implemented using <<, it may work with anything that has the << method now, but you run the risk of something breaking if the implementation changes to use different or additional methods. If you document a method like this, you give the method implementation freedom to use a wide range of methods, but limit the caller to objects that implement that entire interface. Of course that is not the duck-typing or ruby way. The duck-typing way is to document what capabilities you want/need from an argument and that's it. This gives more freedom to the caller and less to the method implementation. > > 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 :-) But, do you ever use the intermediate versions of the class without the class methods? The way class methods are implemented now uses a meta class of Class that is modified along the way. It didn't have to be done that way. For comparision, look at these two: x = "Hello world!".reverse # returns a new object x = "Hello world!".reverse! # modifies existing object In Java, compare the optimizations that could be done with String (immutable) vs. StringBuffer (mutable). There are many optimizations that can be done in String relative to StringBuffer because it is immutable. I assert the same can be said of mutable vs. immutable classes (or meta classes), but I think the difference is more significant once you get deep into optimizations. ____________________________________________________ Start your day with Yahoo! - make it your home page http://www.yahoo.com/r/hs