Blub is the language you know.

Submitted by Greg Buchholz
on November 20, 2006 - 3:02pm


Pascal Costanza wrote:


But in the general case, dynamic typing and static typing are not compatible. In Common Lisp, there are a lot of cases where you can very conveniently change types at runtime. So a static check of types would be a great burden. Here is my standard example for this:

(defclass person () 
    ((name :initarg :name))) 
 
(let ((p (make-instance 'person :name "Pascal"))) 
    (eval (read)) 
    (setf (slot-value p 'address) "Brussels")) 


There is no chance to see up front whether this program will fail or not, since the user can redefine the class person when (eval (read)) is executed. At that time, the slot 'address could be added to the class person.

I don't see any reason why that's not amenable to static typing... In fact, he's got a pretty good description of what the type returned by that eval is. If we don't want to have an error caused by setting the address slot of "p", then we are going to have to extend the environment so that the (setf ...) gets evaluated in a context which includes a version of "person" with an address slot.

I think Pascal might even be close to understanding why this isn't a theoretical problem, since he's aware of the dispatching on return type which could be used to make this work. In a Haskell-like notation, the type for "read" is "String -> a", which means for any type that the rest of the code is demanding from "read", it'll take a String and try to convert it to that type. For example, take a program that looks like...

main = getLine >>= print . (/2) . read 

...When you run it and enter "6.8" at the prompt, it'll reply "3.4". And if you enter "False", it'll throw an exception "*** Exception: Prelude.read: no parse".

In this particular case, the return type of "read" will be something like "A list, that when evaluated, will extend the environment to include a new version of the person class with an address slot." And somewhere there will need to be a definition of "read" that looks (in pseudo-Haskell notation) something like...

instance Read (A list of symbols, that when evaluated will extend the environment to
include a new version of the person class with an address slot) where

read x = if (regular_expression_match 
              x 
              "\(defclass person \(\) 
                 \((\(.*\))* 
                 \(address initarg :address\).*\)\)")
         then string_to_symbols x 
         else error "try again. or some such"


...of course you'd probably want to write a more generic version which could handle a wider variety of cases.

There. That's a sketch of how it could be accomplished. Now the problem is reduced to merely implementing a language with a type system that understands runtime extension of the environment. I think that would be relatively straight forward. The difficulty would come because I'm guessing that Pascal would also want all the other features of Common Lisp (like mutation, goto, conditions, sub-typing, etc.) which might not mix real well (especially if you want to be able to infer types). Most likely, it is a Ph.D. type research project, not something you bang out in a week or two.

Unfortunately, I don't expect that I can explain things well enough in a short blog post to convince anyone that this is something that you could really, actually do. The only people who would understand would be those who are already intimately familiar with the fancy static type systems like found in Haskell.

So I think what we have here is a classic Blub paradox situation:

By induction, the only programmers in a position to see all the differences in power between the various languages are those who understand the most powerful one. You can't trust the opinions of the others, because of the Blub paradox: they're satisfied with whatever language they happen to use, because it dictates the way they think about programs.

Static and dynamic typing advocates just don't have enough common ground/vocabulary/experience to be able to communicate effectively.

But invoking Blub is a boring, almost pointless exercise, little more than preaching to the choir. So instead I'll posit a slightly different conjecture: it takes a non-trivial amount of time to learn languages higher up on the expressiveness/power hierarchy. And this time might or might *not* be worth it. At a certain point, you might find that the time you would spend learning new languages could be used to fine tune your existing skills, or work on getting actual projects completed. So there's a trade off, and I'll further speculate that the cut-off point for maximal productivity is different for different individuals.

So what's the overall conclusion that can be drawn from all of this? There will be no end in sight to the holy wars fought over the dynamic vs. static typing issue.