Getting Backtraces with Standard ML
By W. Clawpaws on Friday 16 February 2007, 21:10 - Programming Languages - Permalink
I still have a pretty good soft spot for Standard ML. Haskell may be sexier, but whenever I want to get something serious done, I find myself turning to SML.
One of my occasional claims for why I sick with ML is that you can actually debug SML programs (c.f., Haskell, where being laziness makes debugging "interesting" -- great if you want a research project).
But in practice, debugging in SML/NJ can actually be a pain. If you get an exception from one of the library functions, you may end up with an unhelpful error message like this one:
uncaught exception Domain [domain error]
raised at: Basis/Implementation/real64.sml:88.32-88.46
Without any sort of backtrace, you get no clue about where/how the exception was raised.
But it turns out that there is a feature in SML/NJ that lets you get a backtrace. It's just that it's barely documented at all!
It turns out that if you type:
CM.make "$smlnj-tdp/back-trace.cm";
SMLofNJ.Internals.TDP.mode := true;
when you first start SML, and then compile your code, when you get an exception, you'll get a backtrace.
Now, you'll see something more like:
CALL art.sml:52.7-52.55: Art.toIntensity[2]
(from: art.sml:89.38-89.57: Art.emitGray[2].iz)
CALL art.sml:79.27-93.33: Art.emitGray[2]
(from: art.sml:13.26-13.29: Art.for[2])
GOTO art.sml:10.7-13.45: Art.for[2]
(from: art.sml:78.22-93.34: Art.emitGray[2])
CALL art.sml:77.19-93.34: Art.emitGray[2]
(from: art.sml:13.26-13.29: Art.for[2])
CALL art.sml:10.7-13.45: Art.for[2]
(from: art.sml:75.14-93.35: Art.emitGray[2])
CALL art.sml:64.7-98.7: Art.emitGray[2]
(from: ???)
CALL art.sml:249.7-307.9: Art.doMix[2]
(from: ???)
uncaught exception Domain [domain error]
raised at: Basis/Implementation/real64.sml:88.32-88.46
Cool. You've got to wonder though, why people would write a cool and useful feature like this and not clearly tell people about it.