[racket-dev] Racket REPL and GUIs

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Mon Jan 24 22:01:29 EST 2011

In v5.0.99.7, when the plain Racket REPL is blocked waiting for input,
it yields to GUI events. That's different from previous versions, which
would leave the GUI frozen while waiting for REPL input.


More information the change:

In v5.0.99.6, if you start plain Racket and load a GUI program like
this,

 Welcome to Racket v5.0.99.6.
 > (require drracket)
 > 

then the GUI does not respond to any actions. The REPL blocks the main
thread while waiting for input, and the main thread is also the
event-handling thread, so no events get through.

Now that Racket can run GUI programs at all, a stuck GUI when using the
REPL seems likely to confuse and aggravate programmers.

To solve this problem, the reading part of the REPL could be a separate
thread from the main program. If reading is put in another thread, then
the main thread could yield to GUI events while it waits for a
expression read to complete. Meanwhile, putting the read in a separate
thread should be ok; reading code is a different phase from running or
even expanding code, and there shouldn't be races or interaction among
the phases. Separating the REPL and GUI threads is exactly what
`gracket -z' used to do.

Adding a new layer of threads would be a significant change for plain
Racket, however, and threads can create all sorts of unexpected
problems. Even DrRacket doesn't really use a different thread for the
interaction reader; it uses the syntax colorer to determine when input
is ready. We don't want require syntax-coloring infrastructure or any
similar extra layer in plain Racket.

The solution in v5.0.99.7 is a parameter that allows a GUI `yield' to
be interposed right where the REPL would block waiting for input. This
interposition is implemented by wrapping the current input port with
one that yields when no bytes are available. Wrapping a port is a
somewhat roundabout way to make the REPL cooperate with GUIs, but it
directly attacks the problem of blocking, doesn't introduce new
threads, and accommodates readers for different languages.

The new parameter is `current-get-interaction-input-port', which is
used by the default prompt read handler, etc. The default function for
the parameter returns the current input port. Invoking
`racket/gui/base' installs a function that wraps the port to interpose
a yield.

Naturally, `gracket -z' now just uses `read-eval-print-loop' instead of
`textual-read-eval-print-loop'.



Posted on the dev mailing list.