# How are keywords different from symbols?

**URL:** https://racket.discourse.group/t/how-are-keywords-different-from-symbols/959
**Category:** Questions & Answers
**Tags:** question
**Created:** [May 3, 2022, 6:33am UTC](https://racket.discourse.group/t/how-are-keywords-different-from-symbols/959 "2022-05-03T06:33:43Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![MichaelBurge](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/michaelburge/32/727_2.png) [@MichaelBurge](https://racket.discourse.group/u/MichaelBurge)
#### Post date: [May 3, 2022, 6:33am UTC](https://racket.discourse.group/t/how-are-keywords-different-from-symbols/959/1 "2022-05-03T06:33:43Z")

</div>

From a high-level understanding, I tend to think of keywords as being "a closed set of strings determined by your program's source code", while symbols are similar but the domain is at runtime.

Neither usage is strict: You can turn arbitrary strings into keywords and symbols. But generally, keywords are used in function definitions and macros and similar source code-level concepts, while symbols are often used in e.g. keys of hash tables populated at runtime.

At a lower level, Rumble[1] seems to define keywords as symbols: I see a `(define-record-type keyword (fields symbol))` that seems to indicate keywords are a thin wrapper over symbols. And symbols seem to be a primitive concept with `#%string->symbol`[2].

Is the "source code vs. runtime" notion a good way to distinguish them? Or are there deeper differences? (maybe the optimizer treats them differently somehow, or I also saw some primitives that deal with keywords so maybe the files I found aren't relevant) Or should we think of them as a syntax nicety, similar to how brackets and parentheses are different but interchangeable?

Is the definition I found the "true definition" of keywords in Racket? If not, where is that?

[1] [racket/keyword.ss at 448b77a6629c68659e1360fbe9f9e1ecea078f9c · racket/racket · GitHub](https://github.com/racket/racket/blob/448b77a6629c68659e1360fbe9f9e1ecea078f9c/racket/src/cs/rumble/keyword.ss)

[2] [racket/symbol.ss at master · racket/racket · GitHub](https://github.com/racket/racket/blob/master/racket/src/cs/rumble/symbol.ss)

---

<div class="post-metadata">

### Author: ![greghendershott](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/greghendershott/32/98_2.png) [@greghendershott](https://racket.discourse.group/u/greghendershott)
#### Post date: [May 3, 2022, 12:06pm UTC](https://racket.discourse.group/t/how-are-keywords-different-from-symbols/959/2 "2022-05-03T12:06:35Z")

</div>

A correct/complete explanation is above my pay grade, but my attempt:

Keywords are used by macro expansion. The `lambda` macro is an example of using keywords for a "keyword arguments" feature. (`lambda` expands to a `plain-lambda` that knows nothing about keyword arguments.)

Unlike symbols, keywords are _not_ expressions.

```scheme
> #:keyword
; #%datum: keyword misused as an expression
; at: #:keyword

```

For macros it's useful to be able to specify a bit of syntax that can't possibly be an indentifier. For example `cond` uses `else` as a magic symbol, but you could imagine instead using a keyword like `#:else`.

- As a macro user, this makes the special syntax parts "pop" more clearly (even if the ergonomics of typing "#:` aren't amazing).

- As a macro implementer, you don't need to worry about whether `else` has some binding, or remember to tell `syntax-{case parse}` that `else` should be treated as a literal (matched only for its symbolic value).

The `syntax-parse` system has a syntax class `expr` which matches everything _except_ keywords. For example in your template you could use `foo:expr` to match any value (keywords aren't values). And you could use `#:else` to match exactly that keyword.

* * *

I feel like this explanation is at best impoverished, and possibly incorrect, but hopefully it will nudge people to correct it. 😄

---

<div class="post-metadata">

### Author: ![spdegabrielle](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/spdegabrielle/32/95_2.png) [@spdegabrielle](https://racket.discourse.group/u/spdegabrielle)
#### Post date: [May 3, 2022, 12:18pm UTC](https://racket.discourse.group/t/how-are-keywords-different-from-symbols/959/3 "2022-05-03T12:18:56Z")

</div>

I think Racket uses the term keyword to mean a specific thing, as defined in the Guide: [3.7&nbsp;Keywords](https://docs.racket-lang.org/guide/keywords.html#%28tech._keyword%29)

In lots of programming languages keyword is a synonym for ‘reserved words’ that are a fixed list of symbols that you cannot/must not/or should not redefine.

My understanding is that Racket, along with other schemes, doesn’t have that restriction, and you can redefine what symbols bind to. I believe lexical scope stops this from being a disaster in Racket, with parameters available for when you want to redefine what a symbol resolves to at runtime.

Edit. Just saw Greg’s response but I’ll leave this here anyway.

---

<div class="post-metadata">

### Author: ![mflatt](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/mflatt/32/6_2.png) [@mflatt](https://racket.discourse.group/u/mflatt)
#### Post date: [May 3, 2022, 12:34pm UTC](https://racket.discourse.group/t/how-are-keywords-different-from-symbols/959/4 "2022-05-03T12:34:42Z")

</div>

Adding to the other replies: the purpose of a keyword is to _not_ be an expression.

For example, in `(do-something #:verbose? #t)`, it's clear that `#:verbose?` makes the `#t` a keyword-based argument and not a positional argument, because a `#:verbose?` by itself is not an expression and therefore cannot be a first by-position argument to `do-something`. You can always quote a keyword to make it an expression, but a quoted keyword is syntactically different than the keyword by itself.

The non-expressionness of a keyword makes it useful in syntactic forms other than function calls, too. In a syntactic form like `struct`, keywords delimit optional subforms with little risk that a keyword intended to start a new subform will be accidentally treated as an argument of a preceding subform. Compare to `define-record-type` in R6RS, which relies more on parentheses to group identifier-tagged subforms with their arguments.

---

<div class="post-metadata">

### Author: ![dstorrs](https://avatars.discourse-cdn.com/v4/letter/d/898d66/32.png) [@dstorrs](https://racket.discourse.group/u/dstorrs)
#### Post date: [May 3, 2022, 5:44pm UTC](https://racket.discourse.group/t/how-are-keywords-different-from-symbols/959/5 "2022-05-03T17:44:17Z")

</div>

Also, keywords, symbols, and string constants are interned but 'manufactured strings' are not. Therefore:

```scheme
> (eq? "foo" "foo")
#t
> (~a 'foo)
"foo"
> (eq? "foo" (~a 'foo))
#f
> (eq? 'foo 'foo)
#t
> (string->symbol "foo")
'foo
> (eq? 'foo (string->symbol "foo"))
#t

```
