Newsgroups: comp.object

Big, but not terribly argumentative. I attempt to explain myself rather than to
indulge in picking.

In article ... Bob Hathaway <objsys@netcom.com> writes:

   In article ..., kers@hplb.hpl.hp.com (Chris Dollin) writes:
   [On static typing and multi-methods]

   I'm giving up if we don't see eye to eye on this after this posting!-)

Well, Bob, I asked a *question* (which you've deleted), about whether
such-and-such was what you'd consider static or dynamic typing. I was
attempting to establish a framework in which we might end up agreeing that the
difference in out views was (at least partially) because we used different
words for the same thing, or the same words for different things.

   Static typing means types are available at compile-time.  Saying a
   language is "statically typed" infers it is not "dynamically typed" which
   means types are available at run-time. 

You see, we already differ, at least in terminology. I see no reason why type
information should not be available at run-time, even in a language which I'd
call ``statically typed''. I'd characterise the difference (the extremal
difference, not necessarily the typical one), as being that, in a ST language,
types are *only* available at compile-time. In a DT language, they are *only*
available at run-time. [I stress; these are the *extreme* cases.]

Incidentally, I do not restrict the discussion to just OO languages, since the
distinction seems to make sense in a wide variety of classical (and novel)
languages. But, taking your paragraph above as a statement of your intentions,

   Dynamically typed languages dispatch based on the dynamic types of 
   arguments.  This is *not* possible with (strictly) statically typed 
   languages because dynamic types are *not* available.  

And by dispatch I presume we both understand the act of (the language, as
represented by its run-time support) selecting an implementation (some code)
from a set of available implementations appropriate (in some way) for the
method being invoked.

I read your statement above as saying that a statically typed language *cannot*
make type information available at run-time. I would regard this as an
excessive restriction.

   So some clever people come up with some tricks (such as virtual functions)
   which are dynamically bound but are still resolved at compile/link time. 
   And some maintain types in their programs (a la Coplien) and emulate
   dynamic typing in an ad hoc way.  

Yes, and this seems tantamount to agreeing with my remark above -- you *need*
some form of type information to be available at run-time.

   In other words (and for the last time), you can't switch on dynamic types
   if (by definition) they aren't there!  And multi-methods are dispatched at
   run-time (dynamically).  

Would it be correct for me to read you as saying ``You can't have multi-methods
in languages which are so statically typed that no type information is
available at run-time''? If so, I think you are wrong, for two reasons.

The first is just this: that I don't think such statically typed languages are
particularly useful for writing (OO in particular) code. The fact that people,
such as Coplien, have to invent ways of making dynamic type information
available, in order to write perfectly reasonable programs, seems suggestive.

Here's my position on dynamic vs static typing:

I see objects (values, things, whatever; the abstract stuff we use to do maths
and programming and so forth) as having, in and of themselves, types (which are
the names we give to certain shared properties). There are certain operations
we perform on these values [such operations, of course, might be values
themselves] -- for example, addition, or printing. These operations are not
everywhere defined -- adding a string to a function, or testing a page to see
if it's less than a window -- and we often call these things ``type errors''
because the operation is inappropriate for a whole class of values which have
(or don't have) a particular type.

If the notation we use to describe these values and operations only permits us
to recognise a type error when it is committed -- that is, when an operation is
actually applied -- then we may say that it is dynamically typed. Sometimes we
would like to detect errors earlier, and we place limitations on the notation
to enable us to compute *in advance* whether a type error might occur. Scripts
in such a notation, where the rules have enabled us to eliminate all
possibility of type errros, are said to be in a statically typed notation. 

Sometimes this allows us to interpret scripts without ever needing to refer to
the type information. In this case, a programmed implementation may even
dispense with recording it. Sometimes knowing the type information in advance
allows us to make such programmed implementations more efficient.

Sometimes people are so blinded by the effectiveness of certain kinds of
restriction that they cannot realise that it's just one kind of tradeoff. Such
people often deny that, for example, what happens when 1 is divided by 0 is a
``type error'', because they have an impoverished notion of type -- one
suitable only for efficient computation at compile-time.

So there's my view on static typing: a compile-time approximation to the real
thing. 

[Note also that there's a well-respected school of thought that makes things
like 1/0 perfectly resonable: it's a value in the range of /, but you *cannot
know which one*. This notion of underspecification is used in, for example, the
HOL theorme-prover, and for that matter in our very own HP-SL specification
language. You can rescue some of the other approaches tools by regarding
certain kinds of underspecification as ``bad'' in the same was as type errors
are regarded as ``bad''.]

   And your (elided) example doesn't seem relevant.

It was there, if I recall, to give me a framework in which I could ask the
question about static vs dynamic typing. Alas, I did not save my message, and
it has now expired. 

   >[I'm sure I've asked you this before, Bob, but what's the difference
   > between a ``dynamic'' function and a ``static'' one?]

   Whether the method/function selection is performed at compile-time (static
   typing, e.g. C++, Eiffle) or at run-time (dynamic typing, e.g. CLOS,
   Smalltalk).

OK. [I think it's a rotten term, because it's the *selection* that's static or
dynamic, not the function; and I can imaging cases where the selection could be
static in one place, dynamic in another. But no matter.]

   >   [8th time]
   >8 repetitions of the same presumed information does not teaching make.
   Excuse me, but I think this makes 10.  And its not "presumed" information.

Have you been listening? You're NOT GETTING THROUGH. Saying the same thing over
and over again *does*not*work* as a teaching device. I am *presuming* that what
you have to offer is information. I am sure that you believe that it *is*
information (rather, knowledge). But, until I can make sense of it, it's not
information (or knowledge) for *me*. 

   >   Chris and I first got into it when Chris claimed that hierarchical
   >   restrictions on packages were a good idea!  [This hasn't been popular 
   >   lately and nor was it with me back then]
   >
   >Perhaps you could also explain to me what you think I meant at the time, 
   >since your description of it does not accord with my thinking about 
   >packages *now*, and I don't think I've moved position much in the past 
   >couple of years.

   I simply argued there should be no hierarchical restriction and you argued
   there should be because generics could always be used to solve the problem.
   I believe I was pointing out the extreme convolution and added complexity
   required to do so as opposed to the "natural" graph solution.

Are you sure this was me? What was the problem we were discussing at the time? 

[I have relics here of a discussion on programming paradigms, what made
languages OO, how languages should -- or should not -- be constructed, dynamic
vs static typing, whether the failure of AI is because Lisp is such an
unnatural language, and whether various languages ``have'' uder-defined
operators. There's a couple of sentences about packages, but nothing I can
construe as the position you're attributing to me. Perhaps I didn't keep the
mail.] 

I'm certainly in favour of using ``generics'' (parameterised types) where it
makes analysis and design of systems and softare easier. But I know I've argued
in the past *against* imposing a heirarchy on package-like things (for example,
Pop11 sections [support comp.lang.pop!] have an import-export hierarchy that I
find dreadful, and I've said so for several years), so I'm not sure what I said
to Bob, or how he interpreted it.

   >CLOS sees there being two activities, that of defining/declaring generic
   >functions (which are about interfaces) and that of defining/declaring
   >methods for implementing that functionality *for particular argument
   >combinations*.
   >
   >Hence my remark that methods, on their own, were NOT enough; you need [*1]
   >the generic functions to invoke them.

   Thanks for the CLOS summary.  But I don't see why generic functions are
   necessary.  Just leave them out, Chris and you'll see all is well.  Really,
   try an example by declaring a generic function and methods and simply delete
   the generic function (which I'm not sure is even required in CLOS).  I can
   see how to implement the system and I don't see any loss - not with method
   combination, individual methods, or anything else - all is still well.

That's because if you leave out the definition of the generic function, the
first method you define for it will cause CLOS to *create* a generic function
for that method (name).

There's still a generic function there. And it's used as a place to hang
information about *all* its methods -- such as the precedence order for
resolving ambiguities (eg, the default left-to-right ordering), and the form of
the argument list (eg, are keyword arguments permitted? &rest arguments? etc).

In short, generic functions are *necessary* in CLOS. But it's not *necessary*
that you, the programmer, write a generic function definition.

``Although it is not necessary to document the interface explicitely by means
of DEFGENERIC,as we do here, doing so often makes it easier for other people to
learn how your program works, and provides guidelines for programmers who wish
to extend the program.'' 

``A DEFGENRIC form establishes a parameter pattern that must be followed by all
methods for that generic function.''

[Keene, Object-Oriented Programming in Common Lisp, p29]. 

``A generic function specifies only the interface. The implementation of the
generic function does not exist in one place; it is distributed across a set of
*methods*.'' [ibid, p9]

And that condescending tone won't work with me. I've tried it on too many
people myself to capitulate to smarm.
--

Regards,    | "If taking devious pains was a sign of laziness, he was quite
Kers.       | prepared to call Hazelton the laziest man alive." Blish (m-o-l)