Excellent post, as usual! It really is a cool feature to run your program, see it crash, and then start opening up objects in the navigable stack trace, prodding their innards (recursively as necessary) until you finally see the list of config parameters was erroneously nil, or something. That’s only ever half of debugging, of course, but that half is nice and quick since you don’t have to add debugging print statements everywhere.
That’s not only a convenience, but could be critical: what if you’ve been looking for this bug for ages, and it’s hard to reproduce? You can’t just go back and add print statements, because that bug might not happen again for a long time.
This next part is a philosophical argument: why do dynamically typed languages, which have all these runtime requirements, not incorporated the same runtime debugging facilities that Lisp and Smalltalk programs have had for literally decades? Why doesn’t Lisp take over the web?
As far as I know, even though Clojure has nifty tools like cloure.inspector, it will still unwind the stack on an exception because of the semantics of Java. The supposed “modern” Lisp, removing features Common Lisp already had.
(If someone knows how Scheme fairs in this regard and can illuminate me, I would appreciate it)
Oh, and I’ll wager another advantage that Lisp has in the way you program. It’s perhaps quite common to “defensively program”, which should mean use static type systems and have complete program totality, but typically means “add a lot of try-catch statements, print very verbose errors, so it becomes very obvious what went wrong at exceptional circumstances”. This adds a substantial amount of noise to programs.
If knowing that getting in a minor vehicular accident will be covered by your car insurance plan, doesn’t that make you less inclined to drive painstakingly carefully?
If you knew that on an exception, your stack wouldn’t unwind, and you’d be able to interactively inspect the entire stack and all objects in scope, would you program so defensively?