Uninterned Symbols

by Wolfgang Corcoran-Mathe

Status

For editor's use only. Please do not edit this section.

??? the draft/final/withdrawn status of the SRFI, information on how to subscribe to its mailing list, and important dates in its history. The editor will add this section.

Abstract

An uninterned symbol is not the same as any other symbol, even one with the same name. These symbols are useful in macro programming and in other situations where guaranteed-unique names are needed. A lexical syntax for uninterned symbols is described, allowing uninterned literal symbols to appear in program source and macro templates. A survey of uninterned and uniquely-named symbols in Scheme is also provided.

Table of Contents

Issues

None at present.

Rationale

A characteristic property of symbols in Scheme is that “two symbols are identical (in the sense of eqv?) if and only if their names are spelled the same way” (R7RS section 6.5). Such symbols are traditionally known as interned symbols. It is sometimes useful, however, to create uninterned symbols that are different from all other symbols, even those with the same textual name.

Many Scheme implementations provide uninterned symbols, and they are also part of the ANSI Common Lisp standard. Their use is almost mandatory with unhygienic macro systems (like that of Common Lisp), where they are used as hidden names that cannot be accidentally captured. This issue is largely solved by Scheme’s hygienic macro systems, but uninterned symbols still have their uses in Scheme macro programming. They can be used as unique keys shared between communicating macros or procedures, for example, since there is no possibility of collision between uninterned and user-created symbols.

The traditional way to create a unique symbol is through a gensym procedure. The name of this procedure is ubiquitous: it dates back at least as far as LISP 1.5, and a variant of gensym is provided by almost every Scheme implementation. It should come as no surprise that the behavior of these gensym procedures varies widely; in particular, many gensyms return interned symbols (see the survey below for details). To increase compatibility with existing implementations, this document specifies generate-uninterned-symbol, a gensym-like procedure, and another constructor, string->uninterned-symbol, which is consistent across the Scheme implementations that provide it.

Specification

In this document, a symbol’s textual name refers to the string returned when symbol->string is invoked on the symbol.

An uninterned symbol is a symbol (in the sense of symbol?) which is not identical (in the sense of symbol=?) with any other symbol, even a symbol with the same textual name.

Uninterned symbols do not support the write/read invariance described in R7RS section 6.5: if an uninterned symbol is written out with write and then read back in, the resulting symbol is not identical (in the sense of symbol=?) to the original symbol.

Procedures

(string->uninterned-symbol string)uninterned-symbol

Returns an uninterned symbol with a textual name given by string.

(symbol-interned? symbol )boolean

Returns #t if symbol is an interned (ordinary) symbol, and #f if it is uninterned.

(generate-uninterned-symbol [prefix])uninterned-symbol

Returns an uninterned symbol with a textual name that is likely to be unique. If the optional prefix argument is provided and is a string / symbol, then prefix / the name of prefix is prepended to the resulting symbol’s name.

Rationale:

generate-uninterned-symbol duplicates the behavior of gensym in Scheme implementations that provide uninterned symbols (and in which gensym returns an uninterned symbol).

Implementation (informational discussion):

Following Common Lisp, many gensym implementations use a non-negative integer counter, a representation of the value of which is appended to the name of the returned symbol. Each call to gensym increments this counter. Other implementations use Universally Unique Identifiers (UUIDs) (ITU-T Rec. X.667, ISO/IEC 9834-8:2014) as names.

Lexical syntax

Uninterned symbols are written using the notation :|identifier|, where identifier belongs to the class of valid Scheme identifiers defined in R7RS § 7.1.1. Example:

(symbol->string :|srfi|)"srfi"
(symbol-interned? :|srfi|)#f

More formally, this SRFI extends the syntax of Scheme as described in § 7.1 of the R7RS as follows. The following production is added to § 7.1.1:

uninterned symbol:| identifier |

The following production of § 7.1.2 is extended:

simple datumboolean | … | uninterned symbol

Similarly, in § 7.1.3:

self-evaluatingboolean | … | uninterned symbol

And in § 7.1.5:

pattern datumboolean | … | uninterned symbol

Prior art

Summary of existing support for uninterned symbols, gensym, and related forms in Scheme.
Implementation Uninterned symbols gensym gensym prefix argument gensym interned string->uninterned-symbol
Bigloo No Yes String or symbol Yes No
ChezScheme Yes Yes String Yes Yes
CHICKEN Yes Yes String or symbol No Yes
Cyclone No Yes String or symbol Yes No
Gambit Yes Yes Symbol No Yes
Guile Yes Yes String Yes No
Ikarus No Yes String Yes No
Kawa No No* n/a n/a No
Larceny Yes Yes String No No
Loko Yes Yes None No No
MIT/GNU Scheme Yes No† n/a n/a Yes
Racket Yes Yes String or symbol No Yes
TinySCHEME No Yes None Yes No

*: Kawa includes a zero-argument gentemp procedure that returns an interned symbol.

†: MIT/GNU Scheme provides generate-uninterned-symbol, an extended version of the procedure described above.

ChezScheme

Chez provides interned “gensyms” which are distinguished by the gensym? predicate. Chez’s gensyms have “pretty” and “unique” names. The former are created immediately and the latter are generated lazily using an internal prefix and counter, which are accessible through parameter objects. gensym->unique-string returns the unique name of a gensym.

Chez’s gensym procedure takes optional pretty-name and unique-name string arguments. The latter argument allows the unique name of one gensym to be given to another; thus, distinct gensyms that are equal in the sense of symbol=? can be created in Chez.

See section 7.9 of the ChezScheme User’s Guide for further details.

Common Lisp

Uninterned symbols are used extensively in Common Lisp macro programming. The Common Lisp HyperSpec specifies MAKE-SYMBOL (analogous to string->uninterned-symbol) and GENSYM procedures that construct uninterned symbols. The names of the symbols returned by GENSYM usually include the value of *GENSYM-COUNTER*, a non-negative integer variable, which is incremented by each call to GENSYM. (This behavior can be circumvented by providing an explicit suffix to GENSYM. See the CLHS for details.)

Since Common Lisp does not have Scheme’s distinction between symbols and identifiers, the implications of internedness are much broader in Common Lisp. For example, objects named by uninterned symbols are, in effect, private to the package in which they were defined. A full discussion of uninterned symbols in Common Lisp is beyond the scope of this SRFI.

Implementation

A portable implementation of uninterned symbols is impossible. In Scheme implementations that provide them (see the table above), uninterned symbols and string->uninterned-symbol are generally compatible with this SRFI.

Many Scheme implementations maintain a table of symbols, indexed by name. When a symbol is created, its name is looked up in this table; if a symbol with that name exists, it is returned; otherwise, a fresh symbol is added to the table. In implementations that use this or a similar strategy, uninterned symbols may be provided by simply skipping the table-lookup and insertion steps.

Acknowledgments

Thanks to Daphne Preston-Kendal for pushing for this SRFI and to Marc Nieper-Wißkirchen for challenging almost everything in it.

Thanks to those who provided reviews and commentary via the SRFI mailing list or the #scheme IRC channel.

References

Alex Shinn, John Cowan, & Arthur A. Gleckler, eds., Revised7 Report on the Algorithmic Language Scheme (R7RS Small) (2013). Available on the Web.

Kent M. Pitman, et al, eds., Common Lisp HyperSpec™ (CLHS) (1994). Available on the Web.

Cisco Systems, Inc., Chez Scheme User’s Guide (2015). Available on the Web.

© 2025 Wolfgang Corcoran-Mathe

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


Editor: Arthur A. Gleckler