rentsch@unc.UUCP (02/16/87)
Something about Paul Asente's article (see below) disturbed me. Not that his remarks are off-base -- on the contrary, they are quite to the point, and the questions are good, even key. No, what disturbed me is that I had such a difficult time coming up with satisfactory answers, even though I "knew" that unbounded polymorphism (specifically in the sense of, e.g., 'Collection' in Smalltalk) is a "good thing". At some level I agree with what he says, but in another way I disagree emphatically. Upon reflection I discovered a seemingly minor, but in reality fundamental, ambiguity of meaning which explains the dichotomy. This ambiguity is explained at the end of the message, with an occasional side issue between here and there. Those who are not interested in side issues may skip to "THE MAIN POINT" later in the posting. In article <278@figaro.STANFORD.EDU> asente@figaro.UUCP (Paul Asente) writes: > In case it wasn't clear from my original posting, it is not polymorphism > that I find questionable, it's unbounded polymorphism. In each of the > examples in Stanley Shebs' article, you are chosing a type out of > a limited set that you know beforehand. Even Simula allows that, and > it can be appropriately type-checked. What I find of dubious usefulness > and even more dubious stylistic practice even if it were useful is > creating a data structure having no idea of what goes into it. Can > you actually think of an example where you would want a queue that > allowed you to enqueue absolutely anything? If you know what's going in, > it may be more convenient to program it with no element type checking > than to set up subtypes of the queue elements for the types you know > are going in, but is it really good style? Side point: when writing an aggregate class (such as Queue, Stack, Collection, or Array), I find it helps rather than hurts to have no preconceptions about what is going to go into the aggregates. And it is certainly very useful to have such aggregates lying around, ready for use, for anything one wants to put into them. It is really wonderful to pick OrderedCollection, for example, up off the software shelf and plug it in knowing it is going to work. When I use such classes I am *glad* that whoever wrote them did not concern himself with what would go into them. Main issue (preview): I draw your attention to "... having no idea of what goes into it", and " ... allowed you to enqueue absolutely anything". We will return to these. > One final point...if you REALLY need a queue with anything in it, > languages like CLU allow you to sidestep the type system by using > a predefined type that is the union of all types. But you don't > have to sacrifice the advantages of compile-time type checking > for this one obscure instance. Side point: aggregates and other highly polymorphic uses are not "one obscure instance" -- in my experience, they happen all the time. I don't just mean Collection and its subclasses -- lots of messages take an argument which can be of highly variable type. In those cases it is frequently useful to pass an argument of "unexpected" type. Sorry not to have an example at my fingertips. Side point: for languages such as CLU, we pay a heavy price for that flexibility, because we then have to (explicitly) discriminate on items we extract. Costly in terms of time, costly in terms of code written, costly in terms of exposing the abstraction to its clients. Main issue (preview continues): Note "if you REALLY need a queue with anything in it ... using a predefined type that is the union of all types". The union of all types is exactly the type we need -- or is it? THE MAIN POINT -------------- The question before the house is, Is unbounded polymorphism a good thing? The answer is, That depends on what is meant by polymorphism (unbounded or otherwise). To explain this perhaps cryptic remark, consider the two statements (questions) which more concretely express the question. If asked, Do you have absolutely no idea of what goes into data structure X?, my answer would have to be, No, of course I have *some* idea of what is going into it (or at least what should go into it). I may want to "pretend", for the sake of practicing methodology, that I do not know, but as a matter of fact I do. But, if asked, Do you want data structure X to be able to accept as an argument (for inclusion in X) absolutely anything, my answer is, Yes, definitely! I do want X to be able to include anything I want it to include, which might be -- in some cases, certainly is -- an object of any class whatsoever. The difficulty is the implicit assumption that the two questions are equivalent, and have the same answer. They are not, and they do not. The first asks if I know *anything* about the arguments. The second asks if I know the *class* (or perhaps class set) of the arguments. What I know might or might not be enough information to imply the class (set) of the operand. [Or, I might know even more information -- such as "the argument must be a positive integer".] So, we get back to the term "unbounded polymorphism". Yes, in the sense that an object *of any class whatsoever* is acceptable. No, in the sense that I know *something* (but maybe not the class) which is true of all arguments. The problem is, what that 'something' is, is not always easy to express. Any class? Certainly. No information? Certainly not. But how much information, and how that information is expressed, is so highly variable that it is expressed informally, as an expression of style, rather than formally, as an expression of type declaration. Cheers, and special cheers to Paul, for asking good questions! Tim