Now we move on to a set of three macros, do-all-symbols, do-external-symbols, and do-symbols. These macros allow the code to iterate over a list of symbols as they are known to the Lisp image. The programmer might use these to inspect the execution environment and possibly call code in optional libraries, but there are usually easier ways to achieve that. One place that I have seen it used is similar to the use of weak symbols in the C++ linker. A piece of code can use do-external-symbols to detect collisions and import other symbols into its namespace only when there is no existing function/variable with the same name. The assumption is that there might be some very basic interface that is optionally extended in another file. The extended package can pick out those functions and variables from the basic package that are not re-implemented. Naturally, this requires very tight cooperation between the two interfaces, but I’ve seen it done.
What do these functions do? Well, do-symbols iterates over all symbols available to a package (or the current package if none is supplied). Generally, that’s all the symbols that the package creates, plus all the external symbols in other packages, including all the symbols in the Lisp language itself.
The do-external-symbols macro iterates over all symbols exported by the package (or the current package if none is supplied). This is the one you’re most likely to use.
The do-all-symbols macro iterates over all symbols in all packages. It’s a symbol dump of the Lisp image itself.
Note that do-symbols and do-all-symbols may list some symbols more than once, so if your goal is to visit each symbol exactly once, you’ll have to take steps to skip the duplicates.