Path: utzoo!news-server.csri.toronto.edu!cs.utexas.edu!usc!sdd.hp.com!hplabs!otter.hpl.hp.com!otter!sfk From: sfk@otter.hpl.hp.com (Steve Knight) Newsgroups: comp.lang.misc Subject: Re: Dynamic typing (part 3) Message-ID: <2400034@otter.hpl.hp.com> Date: 15 Mar 91 13:12:40 GMT References: <602@optima.cs.arizona.edu> Organization: Hewlett-Packard Laboratories, Bristol, UK. Lines: 111 gudeman@cs.arizona.edu (David Gudeman) writes: > I thought you had to declare the types of functions in ML... Sort of. ML is a very interesting strongly typed language in which the types of expressions can often be inferred without type-annotations. Scott Schwartz writes: > % sml > Standard ML of New Jersey, Version 0.66, 15 September 1990 > - fun foo x = x + 1; > val foo = fn : int -> int > - fun bar x = x + 1.0; > val bar = fn : real -> real Despite what follows, I commend ML to anyone who is interested in the development of strongly typed languages. But enough of the Mr.Nice stuff and onto the language bashing you're all waiting for. { .. DISGRUNTLED ML PROGRAMMER ALERT ... WARNING ... ... WARNING ... } - foo x = x + 1; val foo = fn : int -> int Ah yes. True enough. Good job the example wasn't this, though .... - fun foo x = x + x; Error: overloaded variable "+" cannot be resolved It was equally fortunate that this example wasn't used either .... - datatype Foo = Bool of bool | Int of int | Fn of int -> int; - fun foo (x as Fn _, y as Fn _) = false = | foo ( x, y ) = x = y; Error: rules don't agree (equality type required) You see it's vitally important that this function is never executed. Because ML doesn't allow comparison of functions, which is arguable, it cannot allow the comparison of data-types which include functions. Even when the programmer has specifically checked against that possibility ..... Another, obviously wicked, faulty program that the type-checker fortunately throws out on its ear before I do myself any damage is ... - val foo = [false, 0]; Error: operator and operand don't agree (tycon mismatch) Notice the very dangerous consequences of using a list containing a boolean and an integer? This is just one of the many cases where the type system of ML is too conservative, in order to provide the user with type inference. - datatype IntOrBool = Int of int | Bool of bool; - val foo = [Bool false, Int 0]; Just look how ML doesn't need type declarations! I hope the intelligent reader is beginning to get an idea how this splendid type inference is achieved. Polymorphism is very nice, too. I thought I'd construct an updateable reference to the empty list. Whoops! (ML is primarily a functional programming language. The interaction between imperative data structures and polymorphism isn't all one might desire.) - val x = ref []; Error: nongeneric weak type variable x : '0S list ref Gosh. A jolly good job I was protected there. That could have led to a terrible run-time error. The other elegant aspect of the ML type inference system is its ability to resolve the most general type of an equation. In this function "f", the first parameter is never used. So the type inference system deduces that it can be any value it likes ... - fun f x y = if y = 0 then 0 else f f (y-1); Error: operator is not a function As you can see, modern programming languages that support polymorphic type-checking and type-inference give you all the security and performance enhancements of a strongly typed language and all the flexibility and convenience of a dynamically typed language. Yes you certainly get excellent performance from ML. It is not possible to write a polymorphic hash-function. So you can't write polymorphic hash-tables. So you can't write reusable-code for hash-tables. So people use linked lists. Good job it goes fast. (Actually, this is more than a little unfair. You only have to write out hash-functions for each type used in a hash-table. This isn't *really* acceptable but you can sort of live with it. Also some folks, like us, use binary trees rather than linked lists, which makes the comparison less ludicrous.) { END OF MAD RAVINGS ... } My belief is that, to date, there's been no programming languages that gives the obvious benefits of strong typing without some significant penalty. The penalty is typically both superfluous type-declarations in the program and the elimination of valuable programming idioms. (Furthermore, the issue of performance is greatly complicated by the elimination of these idioms.) Unsurprisingly, I am inclined to believe that strong Vs dynamic typing is an unresolved debate. In practical terms, it is still horses for courses. When writing low-level code, strong typing is (in my view) invaluable. When writing in "very" high-level languages, such as Lisp or ML, the penalties are less tolerable (in my view) and, on balance, I prefer dynamically typing. One of the under-explored regions of this topic is that of heuristic type- checking for dynamically typed languages. My belief is that this hybrid approach can be made effective enough to be useful. I know the Scheme folks have made progress in this area but I've not kept up to date on it. Steve