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

Another alternative (Re: format strings are the Right Thing)



From: Paul Schlie <schlie@xxxxxxxxxxx>
Subject: Re: format strings are the Right Thing
Date: Mon, 29 Dec 2003 14:52:39 -0500

> Good:
> - it does likely satisfy most basic static text formatting requirements,
> and doesn't stress implementations/memory by potentially producing large
> intermediate strings; however there are other ways to skin the same cat.
> 
> Bad:
> - format control is disassociated from the data itself (as it's embedded
> within the the constant text field), thereby inhibiting the ability to
> compose formatted text, and/or variable formatting, as a function of control
> state or variable data at run time; which is likely it's true flaw.
> 
> Ugly:
> - a function that may return nothing or a string, dual semantics?
> - the constant text and formatted variable data parameters don't appear
> in the same linear order as the resulting composed text/string/stream;
> basically making the composition of the less ideal and likely error prone.
> 

I got an impression that this format string discussion has similarity
to the regexp pattern language---it defines a mini-language,
it has long history tons of variations, it is concise in typical
usage but can't be composed well and tend to produce an
incomprehensible code when one try to push it too hard.
And Olin Shivers showed a solution, SRE.

Can't we do the similar thing here?
I haven't thought it out well, but the basic idea is like this:

[macro] sfmt <SFMT-SPEC> ...
Generates a "formatter" closure.  Which takes output port and list of
args, and emit the formatted output to the given port.

SFMT-SPEC ::
  <string>                ; literal string to be displayed.
  (write [limit N])       ; take next arg and write it (up to N chars)
  (display [limit N])     ; take next arg and display it (up to N chars)
  (integer [width N][pad C]) ; format as integer
  (float [width N][precision P] ...) ; format as flonum
   ;; and so on ...
  (cl-formattr <string>)  ; traditinal CL-style format string

And the ability to insert evaluated expression in SFMT-SPEC will allow
the programmer to insert other formatter closure into SFMT-SPEC template.
(But I have an uneasy feeling about the "implicit backquote" feature
of SRE... it looks like it make difficult to write a macro that
generates SRE, though  I haven't used SRE extensively so I can't tell
for sure).

The legacy format can be defined easily, to support the legacy code:

[procedure] format output-port string . args
 == ((sfmt (cl-formatter string)) output-port args)

[procedure] format string . args
 == (let ((out (open-output-string)))
      ((sfmt (cl-formatter string)) out args)
      (get-output-string out))

We could also expose low-level build-in formatter procedure,
which could be similar to the one Paul showed.

Issues:
 - What should formatter closure return? - you might want to
   switch behavior by whether the output is chopped by the length
   limitation or not, for example.   Also the you need to know
   how many args are consumed by other formatter procedure embedded
   in SFMT-SPEC.
 - How to handle reordering of the arguments?  Reordering makes
   composition of formatters difficult, but is there a better
   way to support internationalization of formatting templates?
   (maybe a named argument instead of positional argument?)

--shiro