Search code examples
exceptionhandlesmlnjraise

How do I get an unhandled exception to be reported in SML/NJ?


I have the following SML program in a file named testexc.sml:

structure TestExc : sig
               val main : (string * string list -> int)
               end =
  struct

  exception OhNoes;

     fun main(prog_name, args) = (
       raise OhNoes
     )

end

I build it with smlnj-110.74 like this:

ml-build sources.cm TestExc.main testimg

Where sources.cm contains:

Group is
  csx.sml

I invoke the program like so (on Mac OS 10.8):

sml @SMLload testimg.x86-darwin

I expect to see something when I invoke the program, but the only thing I get is a return code of 1:

$ sml @SMLload testimg.x86-darwin
$ echo $?
1

What gives? Why would SML fail silently on this unhandled exception? Is this behavior normal? Is there some generic handler I can put on main that will print the error that occurred? I realize I can match exception OhNoes, but what about larger programs with exceptions I might not know about?


Solution

  • The answer is to handle the exception, call it e, and print the data using a couple functions available in the system:

    $ sml
    Standard ML of New Jersey v110.74 [built: Tue Jan 31 16:23:10 2012]
    - exnName;
    val it = fn : exn -> string
    - exnMessage;
    val it = fn : exn -> string
    -
    

    Now, we have our modified program, were we have the generic handler tacked on to main():

    structure TestExc : sig
                   val main : (string * string list -> int)
                   end =
      struct
    
      exception OhNoes;
      open List;
    
         fun exnToString(e) =
            List.foldr (op ^) "" ["[",
                                  exnName e,
                                  " ",
                                  exnMessage e,
                                  "]"]
    
         fun main(prog_name, args) = (
           raise OhNoes
         )
         handle e => (
           print("Grasshopper disassemble: " ^ exnToString(e));
           42)
    
    end
    

    I used lists for generating the message, so to make this program build, you'll need a reference to the basis library in sources.cm:

    Group is
      $/basis.cm
      sources.cm
    

    And here's what it looks like when we run it:

    $ sml @SMLload testimg.x86-darwin
    Grasshopper disassemble: [OhNoes OhNoes (more info unavailable: ExnInfoHook not initialized)]
    $ echo $?
    42
    

    I don't know what ExnInfoHook is, but I see OhNoes, at least. It's too bad the SML compiler didn't add a basic handler for us, so as to print something when there was an unhandled exception in the compiled program. I suspect ml-build would be responsible for that task.