[comp.object] Type-safe does not mean safe

dlw@odi.com (Dan Weinreb) (10/06/90)

In article <1990Oct5.010703.16019@Neon.Stanford.EDU> craig@Neon.Stanford.EDU (Craig D. Chambers) writes:

							Most
   dynamically-typed languages (i.e. languages that do not type check
   programs statically but instead defer any necessary type checks until
   run-time) are strongly typed (e.g. Lisp (at least interpreted
   versions), Smalltalk, Self), since the run-time system ensures that
   only legal (type safe) operations are applied to objects/values.

By the way, just to throw another joker into the conversation (this is
a digression from the main conversation about the meaning of types):

When we talk about a language system that "ensures that only legal
operations are applied to objects/values", I'd like to point out that
there are other legality questions besides ones having to do with
types.

In nearly every implementation of Pascal, Fortran, C, and C++ that I
know about, if you make an array of 7 elements and store a value into
the 10th element of the array, execution of the program will happily
complete the operation, almost certainly clobbering random unrelated
variables and/or objects, creating a bug that is relatively hard to
find.  (I know that there are exceptional implementations, such as
Sabre C; this lack of checking is not a property of the language per
se, but of most implementations of the language.)

In most interpreted Lisp implementations, in compiled Lisp
implementations running on Lisp machines (Symbolics, at least, but I
think all the others too), and in Smalltalk-80 implementations based
on the ParcPlace "virtual machine" implementation (and probably other
Smalltalk implementations too), such an error would be caught at
runtime.  (In compiled Lisps on conventional architecures, often this
runtime checking is not done -- sometimes it depends on the value of
the "declare optimize" flag, etc. -- again, it's a property of the
implementation, not the language itself.)

The same goes for languages with dynamic memory allocation and
freeing, such as C, C++, and PL/I (and probably some Pascal dialects):
in nearly every implementation, it is possible for a program to free
memory while there are still outstanding pointers to that memory, and
then use the pointers without any detection of error, leading to
incorrect results or errors signalled way down the road, making the
bug hard to find.  This doesn't happen in Lisp and Smalltalk, which
use automatic memory deallocation.

Some people on this mailing list have adamantly repeated to all of us,
many times, without fear of contraction, that static typing (typing of
variables, checking at compile time) is *essential* for the
construction of large programs.  However, they don't seem to think
that checking for array-index-out-of-bounds or illegal-memory-reuse
are particularly important.  They also appear to ignore the fact that
lots of very large, complex programs have been developed, debugged,
and sold to users in languages that do not have static checking.

I have spent years developing commercial software products with both
kinds of language systems, and I assure you that it is quite possible
to do large-scale program development in either kind of language
system.  Both static type checking and runtime array/memory checking
are helpful things to have, and the absence of either has certainly
caused me grief at various times.  My experience is that neither is
essential but both are desirable.  On the whole, I feel that the
importance of static type checking is overemphasized; it's just one
of many kinds of automatic checking that aid in program development
and debugging.

rnews@qut.edu.au (10/10/90)

In article <1990Oct5.184609.7942@odi.com>, dlw@odi.com (Dan Weinreb) writes:
> In nearly every implementation of Pascal, Fortran, C, and C++ that I
> know about, if you make an array of 7 elements and store a value into
> the 10th element of the array, execution of the program will happily
> complete the operation, almost certainly clobbering random unrelated
> variables and/or objects, creating a bug that is relatively hard to
> find.  (I know that there are exceptional implementations, such as
> Sabre C; this lack of checking is not a property of the language per
> se, but of most implementations of the language.)

Actually this operation is illegal in ISO Pascal and most (at least
all that I have used) implementations of Pascal will catch this error
at run-time (as will most strongly typed languages that I know of).
Only if you explicitly tell the compiler not to check for such range
errors will you get the problem you state (granted in Turbo Pascal v3
this is the default, but I think that they are the only ones to set
such an idiotic default.)

 ... comment that Lisp and Smalltalk will catch said problem at 
     run-time deleted ...

> The same goes for languages with dynamic memory allocation and
> freeing, such as C, C++, and PL/I (and probably some Pascal dialects):
> in nearly every implementation, it is possible for a program to free
> memory while there are still outstanding pointers to that memory, and
> then use the pointers without any detection of error, leading to
> incorrect results or errors signalled way down the road, making the
> bug hard to find.  This doesn't happen in Lisp and Smalltalk, which
> use automatic memory deallocation.

Good point, and a strong argument for the need for efficient and safe
GC's for all languages that are used for Programming in the Large.

I agree with your comments that these problems that you have stated
are very important and should be handled by any language that is used
for programming in the large.  I also agree with you that strict typing
rules are also very useful for large scale programming as well (though
not as useful as the above two restraints).  Programming large scale
projects without both of these facilites invariably leads to needless
frustrations and bugs (as mine and everyone I know experiences has
shown.)

Au revoir,

@~~Richard Thomas  aka. The AppleByter  --  The Misplaced Canadian~~~~~~~~~~~@
{ InterNet: R_Thomas@qut.edu.au           ACSNet:  richard@earth.qitcs.oz.au }
{ PSI:      PSI%505272223015::R_Thomas                                       }
@~~~~~School of Computing Science - Queensland University of Technology~~~~~~@

klimas@iccgcc.decnet.ab.com (10/10/90)

In article <1990Oct5.184609.7942@odi.com>, dlw@odi.com (Dan Weinreb) writes:
> In nearly every implementation of Pascal, Fortran, C, and C++ that I
> know about, if you make an array of 7 elements and store a value into
> the 10th element of the array, execution of the program will happily
> complete the operation, almost certainly clobbering random unrelated
> variables and/or objects, creating a bug that is relatively hard to
> find.  (I know that there are exceptional implementations, such as
> Sabre C; this lack of checking is not a property of the language per
> se, but of most implementations of the language.)
	Hmmm! I have yet to encounter an implementation of FORTRAN that didn't
	do checking on array bounds during compilation and runtime!

> Both static type checking and runtime array/memory checking
> are helpful things to have, and the absence of either has certainly
> caused me grief at various times.  My experience is that neither is
> essential but both are desirable.  On the whole, I feel that the
> importance of static type checking is overemphasized; it's just one
> of many kinds of automatic checking that aid in program development
> and debugging.
	Agreed!  Actual hard numbers I've been told indicate that only about
	10% of the errors can be caught using static type checking in large
	programs.

dlw@odi.com (Dan Weinreb) (10/11/90)

Yes, you are quite right; I acknowledge that I overstated my case.
There are certainly compilers for Pascal, FORTRAN, and PL/I that
generate array-bounds-checking code, sometimes optionally (and
sometimes by default and sometimes not).  I got carried away from
excessive recent exposure to conventional implementations of C and C++
in which such checking is not available.