# What does #:track-literals do?

**URL:** <https://racket.discourse.group/t/what-does-track-literals-do/3496>\
**Category:** Questions & Answers\
**Created:** [January 15, 2025, 5:33pm UTC](https://racket.discourse.group/t/what-does-track-literals-do/3496 "2025-01-15T17:33:09Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![acarrico](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/acarrico/32/2135_2.png) [@acarrico](https://racket.discourse.group/u/acarrico)\
**Post date:** [January 15, 2025, 5:33pm UTC](https://racket.discourse.group/t/what-does-track-literals-do/3496/1 "2025-01-15T17:33:09Z")

</div>

What does `#:track-literals` do in `syntax-parse`? Why doesn't `define-syntax-class` also have `#:track-literals`?

---

<div class="post-metadata">

**Author:** ![ryanc](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/ryanc/32/71_2.png) [@ryanc](https://racket.discourse.group/u/ryanc)\
**Post date:** [January 16, 2025, 2:43am UTC](https://racket.discourse.group/t/what-does-track-literals-do/3496/2 "2025-01-16T02:43:57Z")

</div>

# Literals and disappeared-uses

Suppose you have a macro like `cond` that recognizes the _literal_ identifier `else` and treats it specially. In Racket, literal identifiers are recognized _by binding_, so `else` is defined somewhere and exported from the `racket` language, etc.

When you use `cond` and have an `else` clause, you'd like DrRacket to tell you that `else` comes from `racket`. On the other hand, DrRacket should _not_ say `else` comes from `racket` in the program `(let ([else 5]) (add1 else))` or in the program `(quote (if then else))`---neither of those are _references_ to Racket's `else`. So how should DrRacket decide what to say?

It has to look at the expanded program, because in Racket expansion is when scoping and references get figured out. So it looks at the expanded program, and whenever it sees a reference to a variable (like `add1`) or primitive syntax (like `quote`) that corresponds to an original identifier, it records the source of the identifier and its origin (see `identifier-binding`). But `cond` and `else` aren't in the expanded program. So there's a convention: when the macro expander expands `cond`, it adds the `cond` identifier to a _syntax property_ named `'origin` on the result expression, and DrRacket looks there too. So that's how it knows to talk about `cond`. There's another convention: the `cond` macro records the `else` identifier in a different syntax property called `'disappeared-uses` on the syntax it expands to, and DrRacket looks there too.

# syntax-parse and #:track-literals

If a macro doesn't bother to add the `'disappeared-uses` property for a literal, DrRacket doesn't see it. The macro expander cannot automatically track literals like `else`, because the knowledge of their interpretation is inside of the individual macros, but `syntax-parse` has patterns and features dedicated to literals, so it can automatically record literals that occur in the input, in a backtracking-safe way. If you include `#:track-literals` directive, then it adds those recorded literals to the `'disappeared-uses` property on the result. (It doesn't do so by default because the result of a `syntax-parse` expression does not have to be syntax, even though that's the most common use.) The `define-syntax-class` form doesn't have the option because the `'disappeared-use` property is customarily only placed on the macro's final result.

tl,dr: Typically, a `syntax-parse` form that implements a macro should use `#:track-literals`.

---

<div class="post-metadata">

**Author:** ![acarrico](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/acarrico/32/2135_2.png) [@acarrico](https://racket.discourse.group/u/acarrico)\
**Post date:** [January 16, 2025, 1:02pm UTC](https://racket.discourse.group/t/what-does-track-literals-do/3496/3 "2025-01-16T13:02:39Z")

</div>

Lucid. This would be a great addition to the syntax-parse documentation. Thank you.
