September 06, 2013
August 18, 2013
The Human Consequences of Dynamic Typing
I agree with Jay McCarthy that static typing is anti-human. I think I can give a slightly more elaborate example of a program that every static type checker must reject, but that is nevertheless correct. Everything below is valid Common Lisp:
(defclass person () ((name :initarg :name :accessor person-name)))
(defmethod display ((p person)) (format t "Person: Name ~S, address ~S." (person-name p) (person-address p)))
A static type checker must reject this program because there is no address field defined in the class person that person-address presumably refers to. However, below is a run of the program in a Lisp listener that runs to a correct completion without fatal (!) errors:
CL-USER 1 > (defvar *p* (make-instance 'person :name "Pascal")) *P*
CL-USER 2 > (display *p*)
Error: Undefined function PERSON-ADDRESS called with arguments (#<PERSON 4020059AB3>). 1 (continue) Try invoking PERSON-ADDRESS again. 2 Return some values from the call to PERSON-ADDRESS. 3 Try invoking something other than PERSON-ADDRESS with the same arguments. 4 Set the symbol-function of PERSON-ADDRESS to another function. 5 (abort) Return to level 0. 6 Return to top loop level 0.
Type :b for backtrace or :c <option number> to proceed. Type :bug-form "<subject>" for a bug report template or :? for other options.
CL-USER 3 : 1 > (defclass person () ((name :initarg :name :accessor person-name) (address :initarg :address :accessor person-address))) #<STANDARD-CLASS PERSON 4130371F6B>
CL-USER 4 : 1 > :c 1
Error: The slot ADDRESS is unbound in the object #<PERSON 41303DD973> (an instance of class #<STANDARD-CLASS PERSON 4130371F6B>). 1 (continue) Try reading slot ADDRESS again. 2 Specify a value to use this time for slot ADDRESS. 3 Specify a value to set slot ADDRESS to. 4 (abort) Return to level 0. 5 Return to top loop level 0.
Type :b for backtrace or :c <option number> to proceed. Type :bug-form "<subject>" for a bug report template or :? for other options.
CL-USER 5 : 1 > :c 3
Enter a form to be evaluated: "Belgium" Person: Name "Pascal", address "Belgium". NIL
CL-USER 6 > (display *p*) Person: Name "Pascal", address "Belgium". NIL
The "trick" is that the Lisp listener allows for interactive modification of a program while it is running. No static type checker can anticipate what modifications will be performed at runtime.
This is not a toy feature of Common Lisp, but something that many Lisp developers rely on. For example, my own ContextL library crucially relies on the very class redefinition feature I demonstrate above. Joe Marshall provides another account how such features can solve real-world problems.