Subject: Re: howto string->symbol
From: Erik Naggum <erik@naggum.no>
Date: 2000/04/04
Newsgroups: comp.lang.lisp
Message-ID: <3163862476772157@naggum.no>

* Tim Bradshaw <tfb@cley.com>
| Sorry, my mistake, that should have been:
| 
| 	(format nil "~A~S" (symbol-name ...) ...)

  I'm not sure this is really good advice.

  we really want to concatenate a few strings to make a new string.  format
  does a whole bunch of weird stuff that may look right, but the exhaustive
  test case is non-trivial to construct, and it really can't be caught any
  other way until you know what you're doing with an exceptionally high
  level of precision and attention to detail.  (since this topic comes up
  every once in a while, a search engine hit rate increaser: static typing
  -- it won't help at all in such interesting real-life cases.)

  a simple mistake like using ~S with symbols involves the *print-case* of
  symbols, which, while some people might be happy with the default, will
  encounter a user who prefers to see lower-case symbol names, the same way
  he writes them, and it bombs in ways mysterious to the uninitiate.

  a simple mistake like using ~S with numbers involves the *print-base* of
  numbers, and if the programmer has the skills to set *print-radix* to
  true while using non-standard read bases, its effects intervene, too.

(let ((*print-case* :downcase)
      (*print-base* 3)
      (*print-radix* t))
  (format nil "~S~S" 'hello 3))
=> "hello#3r10"

  format is exceptionally good at producing output suitable for humans.  it
  is not very good at producing values suitable for the Lisp reader, yet it
  is so often called upon to do that it hurts.  here's a different solution
  that uses the proper tools for the job, in my usual, unhumble opinion:

(with-output-to-string (*standard-output*)
  (with-standard-io-syntax
    (prin1 'hello)
    (prin1 3)))
=> "HELLO3"

  an "optimized" solution suitable for direct consumption for intern, which
  is what's really sought in this case:

(concatenate 'string
    (symbol-name 'hello)
    (with-standard-io-syntax
      (write-to-string 3)))
=> "HELLO3"

  this might look less convenient than the wrong format solution, but
  that's why we have defun.  constructing a new symbol out of constituent
  parts, however that is defined, is (more or less unfortunately) _not_
  child's play -- it is a sufficiently specialized task that even "software
  pattern" arguments that this should be an idiom fail: it is not something
  users are likely to find just one pattern for, and if they find one,
  it would probably be just as wrong as the wrong format solution.  in
  other words, they need to find out how this stuff works, and then apply
  that knowledge to their domain _every_ time.

  incidentally, this is also one of the reasons I favor WYSIWYG print names
  for symbols.  all of this symbol-hacking stuff would be _significantly_
  simpler with agreement on that principle.

#:Erik