[comp.lang.misc] Unbounded Polymorphism: Is it good style?

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