leichter@yale-com.UUCP (Jerry Leichter) (12/13/83)
Strong typing as it is implemented has a couple of problems: a) It's an incomplete facility. Giving a variable a compiler-checked type is essentially an assertion about the values that variable will contain. Originally, in the grand-daddy of all typed languages (FORTRAN), the assertion was based on hardware limitations: I promise to put nothing but integers in this here variable, but I may put real numbers in that there variable. Some additional things got dragged along: The definition of division was different for different "types". Well, it's rarely of great interest to me that a variable is always an integer. PASCAL took a great leap forward in adding some typing information (ranges) that had not DIRECT correlation with hardware representation. In the process, however, it lost the ability to provide complete checks at compile time, and few PASCAL compilers check at run-time either. However, the original basis of type distinctions remains in PASCAL and many related languages: The compiler provides a small, essentially arbitrary set of assertions that it recognizes. Consider that, for a two's-complement machine, I can assert that the TOP bit is 0 (by an range assertion I >= 0), but not that the BOTTOM bit is 0 (I is even - something that might be very nice to be able to say if I is going to be used as a word address on an 11.) b) It requires me to tell the system things that it ought to be able to figure out for itself. If I is used ONLY as a loop counter, the compiler can easily tell that I can only take on integer values. Why should I have to say so? Let the compiler tell ME what it has decided it knows about each of the variables. In particular, let it tell me when it is unable to learn enough about a variable to generate good code (it can always insert run-time checks); then I can come back and provide such information as I have. People object to this approach on two grounds. The first is a religeous belief that "default declarations" are bad, because PL/I used them and we all know that NOTHING that PL/I did was right. The second is the belief that the source code of a program tell a human reader everything about it. I see no requirement for this at all. Let people read compiler listings, which the compiler will then carefully annotate with the "missing" information. With proper design, the annotated compiler output could be use as INPUT to a later compilation; you would just discard the original source and replace it with the improved version. We already do this with pretty-printers for the sake of simple syntactic clean-up; there is no reason not to do it for "semantic cleanup". Finally, my own personal experience, in about 16 years of programming, both in academia and industry, including a large amount of teaching of programming and grading student programs, in a large variety of languages, is that the\ "problem" being solved by most strong-typing systems - compile-time checking for inconsistencies - is just NOT a significant problem in real life. in my own code, I can think of ONE case where a type-confusion caused in problem (in SNOBOL, and in a context that could not even be expressed in a language without dynamic typing). Problems I do find are more subtle and often have to do with order and meaning of arguments to functions that take many argu- ments - but usually there are multiple arguments of the same type so a typing system wouldn't catch them anyway. A more general assertional system MIGHT - and would be an extraordinarily useful thing anyway, much more useful than any static typing system I've ever seen. Consider the interesting question of whether recursive functions should be declared "recursive". At one time, there were arguments for this: After all, a function that is NOT recursive can be executed more efficiently on many architectures (especially old ones) since it can use a static context frame. Besides, on general "strong typing" arguments, I should be warning the reader - and the compiler - about an important fact about my function. "Recursive" declarations have pretty much disappeared. Hardware stack support was a contributer, but there was also the theoretical argument - which I believe I once saw made by Dijkstra - that if a recursive declaration were to be allowed, it should be checked. But the only way to check if that a function is or is not recursive is to compute the transitive closure of the call graph - easy in "standard" PASCAL, with not external functions, for example - from which one could as easily have the compiler decide for itself that the function is or is not recursive. Hence, the declaration is redundant. My claim is that the same reasoning ought to be applied to other type information. -- Jerry decvax!yale-comix!leichter leichter@yale
stevev@tekchips.UUCP (Steve Vegdahl) (12/14/83)
>>It's an incomplete facility ... [providing] a small, essentially arbitrary >>set of assertions that it recognizes. Consider that, for a two's-complement >>machine, I can assert that the TOP bit is 0 (by an range assertion I >= 0), >>but not that the BOTTOM bit is 0 (I is even - something that might be very >>nice to be able to say if I is going to be used as a word address on an 11.) >> ... >>A more general assertional system MIGHT - and would be an extraordinarily >>useful thing anyway, much more useful than any static typing system I've >>ever seen. This is not an argument against strong typing, but rather about the inadequacy of implementations of strong typing. Could Pascal not be extended so that types could include assertions about evenness/oddness, to use your example? Increasing the robustness of a strong typing mechanism seems like a fine idea. >>It requires me to tell the system things that it ought to be able to >>figure out for itself. If I is used ONLY as a loop counter, the compiler >>can easily tell that I can only take on integer values. Why should I have >>to say so? >> ... >>the "problem" being solved by most strong-typing systems - compile-time >>checking for inconsistencies - is just NOT a significant problem in real >>life. >> ... >>Hence, the declaration is redundant. My claim is that the same reasoning >>ought to be applied to other type information. In my programming experience, such checks have aided me in catching a large number of stupid bugs. Having the compiler force you to make such declarations may slightly increase your work, but once you're used to it, and if you have a reasonable programming environment and language, the amount of such work is insignificant. I would suggest that features in a language that increase the likelihood of checkable assertions in a the source code are a good thing. A strong typing mechanism certainly falls into this category. >>religeous [sic] belief that "default declarations" are bad, because PL/I >>used them and we all know that NOTHING that PL/I did was right. I will elide the question of whether PL/I did ANYTHING right, but it is the consensus of the computer scientists that I know that default declarations are bad. I done enough FORTRAN programming in my earlier days to know the grief one can go through because of a variable that is automatically declared because of a typo. Steve Vegdahl Tektronix, Inc. Beaverton, Oregon
davies@uiuccsb.UUCP (12/16/83)
#R:yale-com:-258200:uiuccsb:8900001:000:1107 uiuccsb!davies Dec 15 18:08:00 1983 If you don't believe that automatic typing of variables doesn't cause errors, then you must not have written any large Fortran programs. The first thing I look for when a program is behaving strangely is whether I forgot to declare a variable, and it defaulted to the wrong type. Some Fortran 77 compilers (including Unix F77) have IMPLICIT UNDEFINED which requires explicit typing of all variables. I consider this to be quite a useful feature, which was unfortunately left out of the ANSI 77 standard. The company I work for has implemented a compiler that uses the suggestion of sending the listing produced by the compiler back in as input. Error and other messages are marked in a way that causes the compiler to ignore them the next time. This allows editing of the listing to correct syntax errors, which is very convenient. By the way, we also have the options RECURSE and NORECURSE for procedures etc. NORECURSE produces more efficient code in some cases. This may seem an archaic feature, but we are using this language to implement a large program and have added it for practical reasons.
wls@astrovax.UUCP (William L. Sebok) (12/17/83)
One of the most common causes of errors in my C number crunching programs is forgetting to declare floating point functions to be floating point. It is easy to forget the integer default. -- Bill Sebok Princeton University, Astrophysics {allegra,akgua,burl,cbosgd,decvax,ihnp4,kpno,princeton,vax135}!astrovax!wls
ucbesvax.turner@ucbcad.UUCP (12/24/83)
#R:yale-com:-258200:ucbesvax:4500006:000:2535 ucbesvax!turner Dec 15 15:51:00 1983 /***** ucbesvax:net.lang / yale-com!leichter / 6:17 am Dec 14, 1983*/ ...that the "problem" being solved by most strong-typing systems - compile-time checking for inconsistencies - is just NOT a significant problem in real life. ...Problems I do find are more subtle and often have to do with order and meaning of arguments to functions that take many argu- ments - but usually there are multiple arguments of the same type so a typing system wouldn't catch them anyway. How ironic--just 1/2-hour ago I fixed a bug of this kind. The function took four arguments, only two of which were integers. In pascal (I'm writing in C), they would have been "var integer". The formal parameter names were "ncols" and "nrows"--in that order. The user of this routine confused the order (quite naturally--most of us prefer to say "rows and columns" to "columns and rows"), which blew up his code. If C had better strong typing, I would have solved this by having types "rowval" and "colval". As it is, we limp along, being quite poor programmers by Jerry's definition. We do terrible things like forget argument-order even for functions with small numbers of arguments. I am currently in the position of helping to support some channel-routing code. It has about 40 integer-type variables global to the whole routine. Most of these are indices to very specific arrays. The author didn't type them as being specific subranges. We wish that he had. The algorithm is published, and easily understood, but the code is a mess. Strong typing would have helped both in terms of maintenance and in making the code more self-documenting. (No, I don't claim that strong-typing makes programmers better. But I do believe that better programmers employ it, because they know better than to believe for a minute in their own perfection.) Re: declaration of functions as recursive This is irrelevant to the discussion of the relative merits of strong typing. When is such a distinction important for the kinds of uses to which strong typing is put? "recursive foo()" is a COMPILER-directive, implying that recursiveness is a consideration in producing code that is faster or correctly implemented. It would never be a consideration in a statement like <fn ref 1> := <fn ref 2> where one would certainly want to know that fn2 returned something of a type castable to the return-type of fn1. Jerry is making an argument by analogy, the analogy does not exist. --- Michael Turner (ucbvax!ucbesvax.turner)