Christopher Armstrong
Christopher Armstrong

Reputation: 2307

Why don't I get output from Debug.log in an infinite loop in the Elm REPL?

I'm debugging some code with an infinite loop, but it's difficult, because I can't get any log messages out. Here's a simplified case:

import Debug exposing (log)

f x =
    let _ = log "Hello, world!" ()
    in f x

If I run this at my Elm REPL like f (), it infinitely loops and never prints out "Hello, world!" as I expect it to.

I looked at the implementation of Debug.log (following it to Native.Debug.log), but it just seems to be calling process.stdout.write or console.log synchronously, so I'm surprised that I'm not seeing any output.

Upvotes: 3

Views: 637

Answers (1)

Christopher Armstrong
Christopher Armstrong

Reputation: 2307

This is just a bug in the Elm REPL.

The Problem

I dove into the implementation of the Elm REPL. The relevant function is here: Eval.Code.run

This run function seems to be the function that executes a piece of code. It looks like each line of code is executed in a subprocess, via Elm.Utils. unwrappedRun. There are two problems with the way it runs it:

  • The stdout of the subprocess is not streamed; it's only returned once the whole subprocess is done. So as long as you're waiting for your code to finish evaluation, you won't see anything.
  • If you hit ctrl-c to end evaluation prematurely (which works fine, and returns you back to the Elm prompt), the Elm Repl ignores the stdout that is returned to it. Notice the pattern match for CommandFailed:

Left (Utils.CommandFailed _out err) -> throwError err

The Utils.CommandFailed result helpfully includes the stdout (which is being bound to _out), but this code ignores it and just throws the error.

So basically this isn't anything that weird going on with the Elm compiler or runtime, just that the REPL isn't as good as it could be with respect to logged results.

The Workaround

As a workaround, in order to debug things like infinite loops, you can

  1. put some test code in a new file, Scratch.elm, like x = f ()
  2. compile the code with elm-make Scratch.elm --output scratch.js
  3. run the code with node scratch.js

Then output will be streamed to your terminal.

Upvotes: 6

Related Questions