Gauche Devlog

< Oops - gauche-package regression | Top-level REPL commands >


Write control variables

Oh well. More than a year since the last entry. So many things has loaded into HEAD and I have to wrap it up as 0.9.5. Some small issues to address, though.

As a part of improving REPL experience, I implemented CL-like write control variables. Those like *print-length*. In Gauche it looks like a parameter.

gosh> (parameterize ((print-length 5)) (write (iota 10)))
(0 1 2 3 4 ...)#<undef>

I wanted them every time I accidentally evaluated huge data structure on REPL and just waited Emacs to finish showing it until the end (Ctrl-C can stop Gauche printing it, but it's mostly Emacs that's taking time to fill the buffer, especially when font-lock mode is on.)

By the way, print-base comes handy as desktop calculator for base conversion:

gosh> (print-base 16)
gosh> (print-radix #t)
gosh> 4758375874

Now I've implemented four of various CL's printer control variables, and sit back and am thinking. Are they really useful as they seem to be?

The global nature of those controls is the problem. I'd like to limit print-length on REPL output to avoid excessive output. But doing so globally affects every operation, such as serialization to file or network connection, which is almost certainly undesirable. I can create a custom printer for REPL that changes the controls only when it prints the result, but then I need another set of API to set those values REPL would use.

Worse, now every routine that writes out values expecting it to be read back must be wrapped with parameterize to ensure those control variables are in the default value, otherwise it can be broken accidentally when called with print-level set to 5.

The more I think, the more dubious I became about the CL's choice of making them dynamic variables.

Another idea I had before is to have a "context" object that packages those controls, and you can set it to a parameter, instead of parameterizing individual controls (the name ScmWriteContext in the source was somewhat intended for that, but ended up for different purpose.) With that, the REPL can have just one repl-default-context and use that for just printing.

Recently I got yet another idea; let a port have those controls. We already have port-attributes to associate key-value pairs to ports. For serialization you'll usually create a fresh ports so the chance of inadvertent interference is very low. For REPL output, we can create a wrapper port connected to stdout so that it can have separate attributes, and use it for printing the results.

Some more pondering.

Tags: REPL, 0.9.5

Post a comment