;; I promised a look into the mechanics of the eLisp's global symbol table. Here it is. ;; eLisp's read-eval-print environment uses the obarray global object to store symbols and ;; functions. Each symbol read from the input is entered ("interned") into this array, ;; and any references to symbols go through it, to find the symbol's value or function value, ;; if any, whenever used in an expression. ;; As a matter of implementation, obarray is a vector, used for hash lookups. 0s stand for ;; empty slots (called "buckets") obarray [0 0 pr-ps-file-preview timer-next-integral-multiple-of-time vietnamese-tcvn-unix 0 0 make-mode-line-mouse-map backquote-listify sgml-mode find-sibling-rules help-follow-symbol ...] ;; more: https://www.gnu.org/software/emacs/manual/html_node/elisp/Creating-Symbols.html ;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Creating-Symbols.html#index-obarray-1 (length obarray) ;; with all the empty bins and multiple symbols per bin. This is a very rough ;; estimate of the number of symbols in this session. 15121 ;;; Let's take a snapshot of the defined global symbols at a given time: (defun all-symbols () "Return a list of all symbols in obarray" (let ((syms nil)) ; local list for a snapshot of obarray ; traverse the obarray, for every non-empty slot append the symbol to the snapshot list (mapatoms (lambda (s) (setq syms (cons s syms)))) ; mapatoms uses the global obarray by default syms)) ; return snapshot list all-symbols ;; Things to note about the above code: ;; (1) mapatoms breaks the pure functional style of Lisp programming. It calls the ;; function provided as argument on each symbol, but leaves it up to that function ;; to save, print, or discard its result. Since there is no structure into which ;; these results are collected, the function itself must append them to a list ;; to save them for further examination. ;; (2) the lambda passed to mapatoms appends the symbols to a list, by creating ;; one new cons cell per symbol and adding it to the front of the list, with ;; the former head of the list as the cdr of the new cons cell, which now gets ;; set as the list's new head. This is arguably the cheapest way to glow a list in Lisp. ;; ;; (3) The list starts as a local variable in the (let ..) but gets returned as the function's ;; value. If picked up as some symbol's value in a setq, that value will live on ;; through garbage collection after the let is done. ;; This is the opposite of what happens in C: returning a pointer to a local ;; variable in a function would likely lead to a memory corruption, because by ;; the time you use that pointer the stack memory may be repurposed its contents ;; overwritten or used by something else. (all-symbols) (utf-16-le-dos pr-ps-file-preview utf-7-mac timer-next-integral-multiple-of-time :log vietnamese-tcvn-unix make-mode-line-mouse-map backquote-listify sgml-mode access-label non-ascii selected ...) (length (all-symbols)) 22220 ;; that was a bit silly, because the result of (all-symbols) above did not get assigned to any ;; variable and will be garbage-collected. Next time we'll save the snapshot to compare it ;; with others. ;; Let's create a symbol. It gets created once the reader reads the expression. foobar ;; Lisp error: (void-variable foobar) ;; We could also create that symbol by explicitly reading its name as a string: (read "foobar") foobar (length (all-symbols)) 22221 ;; now joined by foobar, created by read. Foobar has no bindings, but it exists as a symbol. ;; member returns a reference for the first occurrence of the symbol in the list, or nil (member 'foobar (all-symbols)) (foobar ebnf-syntax-buffer menu-bar-frame-for-menubar xterm-function-map gui--set-last-primary-selection window-total-size ethio-input-special-character sql-solid talk-connect cp850-dos lpr-customize cl--slot-descriptor-initform--cmacro ...) ;; let's try another symbol (member 'foobaz (all-symbols)) (foobaz floatp gnus-slave completion--capf-safe-funs process-sentinel ibm850-mac :test floats nyiakeng-puachue-hmong Electric-pop-up-window long-line-optimizations-region-size find-alias-regexp ...) ;; What just happened? Easy: foobaz was read in when the (member ...) evaluation happened. Now ;; it's a symbol, already entered into obarray by the time the read of the (member ..) sexp ;; is done, and this found in the obarray when the expression gets evaluated. ;; Now we take a snapshot of obarray (setq ll (all-symbols)) (utf-16-le-dos pr-ps-file-preview utf-7-mac timer-next-integral-multiple-of-time :log vietnamese-tcvn-unix make-mode-line-mouse-map backquote-listify sgml-mode access-label non-ascii selected ...) (length ll) 22223 ;; read will create 'foobarbaz in obarray, but the snapshot is from before that point (member 'foobarbaz ll) ; so no foobarbaz in the snapshot nil ;; let's repeat this snapshotting experiment a few more times (member 'll ll) (ll show-paren-priority treesit-pattern-expand byte-compile-form-make-variable-buffer-local comm encode-coding-string Buffer-menu-mode-width ispell-output-buffer c-forward-type modus-vivendi vc-version-ediff lp ...) (setq ll1 (all-symbols)) (utf-16-le-dos pr-ps-file-preview utf-7-mac timer-next-integral-multiple-of-time :log vietnamese-tcvn-unix make-mode-line-mouse-map backquote-listify sgml-mode access-label non-ascii selected ...) (length ll) 22223 (length ll1) 22225 ;;; The Common Lisp library has many useful functions for lists. Needs to be imported. ;;; This used to be (require 'cl) in older versions of Emacs, deprecated now. (require 'cl-lib) cl-lib (cl-set-difference ll1 ll) ; all symbols in the first list that don't occur in the second (foobarbaz ll1) ;More about eLisp's list functions: https://www.math.utah.edu/docs/info/elisp_6.html ;; https://www.perplexity.ai/search/list-difference-in-elisp-K51jpFAST7eKy.w_D8GgUw (setq ll3 (all-symbols)) (utf-16-le-dos pr-ps-file-preview utf-7-mac timer-next-integral-multiple-of-time :log vietnamese-tcvn-unix make-mode-line-mouse-map backquote-listify sgml-mode access-label non-ascii selected ...) (length ll3) 22226 (member 'quux ll3) nil (setq ll4 (all-symbols)) (utf-16-le-dos pr-ps-file-preview utf-7-mac timer-next-integral-multiple-of-time :log vietnamese-tcvn-unix make-mode-line-mouse-map backquote-listify sgml-mode access-label non-ascii selected ...) (member 'quux ll4) (quux cl-callf flyspell-auto-correct-previous-pos log-view-message-re diff-current-defun default-boundp configure-info-directory lpr-command isearch-cancel compound-text-with-extensions-dos obarray-make abbrev-start-location-buffer ...) (length ll4) 22228 (cl-set-difference ll4 ll3) (quux ll4) ;; also relevant https://stackoverflow.com/questions/25209134/is-there-any-benefit-to-using-an-obarray-rather-than-a-hash-table-in-emacs-lisp