[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Format strings are wrong




On Dec 27, 2003, at 11:37 PM, Alex Shinn wrote:

The SRFI process isn't just about porting, but also standardizing
libraries.  One of the primary motivations of SRFI-1 was that all
Schemes provided varying levels of add-on list utilities with
incompatible API's.

It's also about getting together and producing something _better_ than what J. Random Schemer or Common Lisper thought up a while ago. Remember FLUID-LET? -- there was once a SRFI about it, but it was ditched because there were several arguments about why it was a bad idea, and better ideas. (Actually, I disagree with the design of SRFI 39 (parameters), too, which could be considered to be one of those better ideas, but that's a different story and not really relevant here.) Likewise, if there are good arguments against format strings, and there are good alternative ideas, why should you let yourself be held down by the old and historically motivated idea? I don't claim that LAMBDA: The Ultimate Formatter is necessarily the best idea -- just as I don't think SRFI 39 is the best idea in the related set of ideas regarding fluid variables --, but I think
it's a better idea nevertheless.

  In this case almost all Schemes at least support
SRFI-28, and many support some or all of the full Common-Lisp format,
so it is definitely something people find useful and should be
standardized.  Many people feel SRFI-48 doesn't go far enough, so
there will likely be at least one more format SRFI.  Perhaps that will
explicitly make the individual formatting procedures accessible as
they are in Dirk Lutzebaeck's implementation, which would give you the
option of using both styles.

Of course, and FLUID-LET is easily implemented and available in lots of places. But that does not make it a _good_ thing. Likewise, formatting strings are easily implemented and available in lots of places; indeed, there are portable implementations for full Common Lisp FORMAT. But CL FORMAT isn't necessarily
a good thing.

Possibly something along the lines of simply adopting the notion that:
(str-fmt ....) [or (string ...) be extended] to accept mixed string, symbol, character and numerical arguments, and produces a string resulting from the
concatenation of its argument's string equivalences

Probably best not to overload string, especially in light of recent
discussions as to just what a character is.  Also, the procedure
should definitely output to a port, not a string.  But even using a
port this becomes inefficient if you inline write's:

  (define (write-to-string x) (with-output-to-string (cut write x)))
  (fmt #t "list: " (write-to-string ls) #\newline)

and likewise for performing different number->string conversions in
the middle of a format.

Formatter procedures can work any way you like; all you need is to pass some different WRITE-CHAR procedure, which allows for even more expressiveness. For instance, you could use SHIFT & RESET to generate a stream from FORMATTER:

  (reset
    (format FORMATTER
      (lambda (char) (shift k (stream-cons char (k)))))
    stream-null)

(Assuming the continuations that SHIFT lets you nab are n-ary. It may also be
better to use BSHIFT & BRESET, but that's diverging from this SRFI.)

This doesn't force you to cons up intermediate strings or even intermediate output ports with a specialized character writer. (One might debate about the efficiency of SHIFT & RESET, which I don't want to right now, as it's utterly
beside the point.)

                         You really have to break it apart as:

  (display "list: ")
  (write ls)
  (newline)

which when compared with

  (format #t "list: ~S\n" ls)

looks clumsy and verbose, especially when you have many of these
throughout a program almost tripling the number of lines, and
especially when you have to wrap them in begins.  Format is very
concise

If we cared that much about conciseness, we'd all be using Perl or GOO. But we
don't care _that_ much.

        and not only lets you re-use the format string in parts of
your program, it lets you easily change it at runtime

The same can be said about formatter procedures.

                                                      (even in an
eval-less Scheme) and lets you load it from things like config files.

But what you're really doing there is just creating a very limited language for formatting; it's equivalent to having a very limited EVAL. Why not use EVAL? You could even write an incredibly simple EVAL that supports only LAMBDA,
function application, and the built-in formatters.

Consider the log files of a server that need to produce customizable
output, like this from my httpd.conf:

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %T %v" full

Or consider the Emacs mode-line-format string which lets you customize
(again at runtime) what appears in your mode-line.  Of course, Emacs
allows nested lists as the format, which may be a consideration for
future format SRFIs rather than consider introducing artificial
nesting with ~<...~> etc.

Formatter procedures can easily be arbitrarily nested however you like.

By keeping the logic in one place format is also much better suited to
things like i18n, and can provide more efficient control over
columnating and padding.

And you don't need to remember obscure formatting directive syntax with obscure single-character main names and strange syntax to go around it (SRFI 29's ~@*, anyone?). Column & padding control are especially easy when you've got full Scheme at your fingertips with which to write formatting routines. It would be trivial to write a FORMAT/PADDING routine that would keep track of the columns
that the sub-formatters write.

All around, format is more consice [sic], more efficient, and more flexible
than the alternatives.  That doesn't mean we couldn't use some more
functional interfaces, but they will likely not replace format.

Concise [sic], I concede; but do you really want _that_ much conciseness? I'd say no, or, as I said, we'd all be using Perl or GOO. (OK, that's a bit of an
overstatement, but you get the idea.)

--
Alex