# Function and macro to define unique values

**URL:** https://racket.discourse.group/t/function-and-macro-to-define-unique-values/1097
**Category:** Show & Tell
**Tags:** macro, today-i-learnt, struct, unique, custom-method
**Created:** [June 25, 2022, 12:34pm UTC](https://racket.discourse.group/t/function-and-macro-to-define-unique-values/1097 "2022-06-25T12:34:54Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![sschwarzer](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/sschwarzer/32/1940_2.png) [@sschwarzer](https://racket.discourse.group/u/sschwarzer)
#### Post date: [June 25, 2022, 12:34pm UTC](https://racket.discourse.group/t/function-and-macro-to-define-unique-values/1097/1 "2022-06-25T12:34:54Z")

</div>

I've seen the idiom

```scheme
(struct unique-value ())

```

to create unique values, for example as default arguments in a function to check with `(eq? argument unique-value)` if anything was passed for the argument.

Since I have only little experience with Racket macros so far, I took this as a motivation to define a macro around this. (But in the end, because of the helper function, the macro itself turned out much simpler than I had expected.) To be useful to as many readers as possible I added comments more extensively than I usually do, even though I certainly learned a lot myself and therefore had added some of the comments anyway. 🙂

```scheme
#lang racket/base

(require
  racket/format
  racket/function)

; Define a helper function `make-unique-value` to generate
; a value of a struct (that only exists locally).
;
; Note that we must return a value of the struct, not
; the struct (`unique-value`) itself because otherwise the
; custom write method isn't applied.
(define (make-unique-value name)
  (struct unique-value ()
    ; See https://docs.racket-lang.org/reference/define-struct.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._struct%29%29
    ; and https://docs.racket-lang.org/reference/Printer_Extension.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._gen~3acustom-write%29%29
    #:methods gen:custom-write
      ; Pre-set the name as the rightmost argument because
      ; the function for `write-proc` must use three arguments,
      ; but we need to get the name somehow into `write-proc`.
      [(define write-proc (curryr unique-value-write name))])
  (unique-value))

(define (unique-value-write unique-value port mode name)
  (write-string (~a "#<unique:" name ">") port))

; Test the helper function.
(define foo (make-unique-value "foo"))
; #<unique:foo>
(displayln foo)

; Macro that wraps the helper function and allows us to use
; the syntax `(define-unique name)`.
;
; To convert the new identifier name to something that can be
; processed in the helper function, use `quote` to convert the
; name to a symbol, see
; https://rmculpepper.github.io/malr/basic.html .
(define-syntax-rule (define-unique name)
  ; Strictly speaking, we don't need `symbol->string` here
  ; because the custom write function formats 'name exactly
  ; like "name", but let's be clear on the intended types.
  (define name (make-unique-value (symbol->string (quote name)))))

(define-unique bar)
; #<unique:bar>
(displayln bar)

```

I wouldn't be surprised if this existed already in a package or even the standard library, but I wanted to experiment with this. 😃

---

<div class="post-metadata">

### Author: ![sschwarzer](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/sschwarzer/32/1940_2.png) [@sschwarzer](https://racket.discourse.group/u/sschwarzer)
#### Post date: [June 25, 2022, 1:08pm UTC](https://racket.discourse.group/t/function-and-macro-to-define-unique-values/1097/2 "2022-06-25T13:08:01Z")

</div>

I just realized that even though the macro does little beyond the helper function, using the macro has the advantage that you can't accidentally define two unique values that print the same (which could be confusing during debugging):

```scheme
(define u1 (make-unique-value "abc"))
(define u2 (make-unique-value "abc"))
u1 ; #<unique:abc>
u2 ; #<unique:abc>
(eq? u1 u2) ; #f

```

On the other hand, if you use only the macro, I think you can't (in the same scope) create multiple unique values with the same printed name:

```scheme
(define-unique u3)
u3 ; #<unique:u3>
(define-unique u3) ; module: identifier already defined in: u3

```

---

<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: [June 25, 2022, 2:03pm UTC](https://racket.discourse.group/t/function-and-macro-to-define-unique-values/1097/3 "2022-06-25T14:03:53Z")

</div>

> [@sschwarzer](#):
>
> I wouldn't be surprised if this existed already in a package or even the standard library, but I wanted to experiment with this.

Experimenting is of course always good. Regarding your [Lorite](https://anathem.fandom.com/wiki/Lorite) hunch: One example I've seen is in [Rebellion](https://docs.racket-lang.org/rebellion/Singleton_Types.html#%28tech._singleton._type%29) by @notjack.

---

<div class="post-metadata">

### Author: ![sschwarzer](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/sschwarzer/32/1940_2.png) [@sschwarzer](https://racket.discourse.group/u/sschwarzer)
#### Post date: [June 25, 2022, 3:02pm UTC](https://racket.discourse.group/t/function-and-macro-to-define-unique-values/1097/4 "2022-06-25T15:02:05Z")

</div>

> [@greghendershott](#):
>
> One example I've seen is in [Rebellion](https://docs.racket-lang.org/rebellion/Singleton_Types.html#%28tech._singleton._type%29) by @notjack.

Of course, Rebellion has _everything_. 🙂 👍

---

<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: [June 25, 2022, 4:40pm UTC](https://racket.discourse.group/t/function-and-macro-to-define-unique-values/1097/5 "2022-06-25T16:40:06Z")

</div>

Would [gensym](https://docs.racket-lang.org/reference/symbols.html#%28def._%28%28quote._~23~25kernel%29._gensym%29%29) do what you want? It produces a symbol that is guaranteed to be unique across the run of a program. Here's what I get in my local REPL:

```scheme
> (gensym) ; 'g6178304
> (gensym "foo") ; 'foo6178305
> (gensym 'foo) ; 'foo6178306

```

---

<div class="post-metadata">

### Author: ![sschwarzer](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/sschwarzer/32/1940_2.png) [@sschwarzer](https://racket.discourse.group/u/sschwarzer)
#### Post date: [June 25, 2022, 6:40pm UTC](https://racket.discourse.group/t/function-and-macro-to-define-unique-values/1097/6 "2022-06-25T18:40:30Z")

</div>

> [@dstorrs](#):
>
> Would [gensym](https://docs.racket-lang.org/reference/symbols.html#%28def._%28%28quote._~23~25kernel%29._gensym%29%29) do what you want? It produces a symbol that is guaranteed to be unique across the run of a program.

That's nice! I'm quite sure now that I had seen this in the past.

Although I like the macro approach a bit more, I like that `gemsym` is in the standard library, so I'll probably use it the next time I need a unique value.

---

<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: [June 26, 2022, 12:37pm UTC](https://racket.discourse.group/t/function-and-macro-to-define-unique-values/1097/7 "2022-06-26T12:37:56Z")

</div>

Also, I forgot to add: gensym has the advantage that it's a procedure, so you can pass it as an argument.

---

<div class="post-metadata">

### Author: ![gus-massa](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/gus-massa/32/507_2.png) [@gus-massa](https://racket.discourse.group/u/gus-massa)
#### Post date: [June 27, 2022, 1:39am UTC](https://racket.discourse.group/t/function-and-macro-to-define-unique-values/1097/8 "2022-06-27T01:39:37Z")

</div>

Why don't you store the name inside the struct?

```scheme
#lang racket/base

(require racket/format)

(define (make-unique-value name)
  (define (unique-value-write x port mode)
    (write-string (~a "#<unique:" (unique-value-name x) ">") port))
  (struct unique-value (name)
    #:methods gen:custom-write
      [(define write-proc unique-value-write)])
  (unique-value name))

(define foo (make-unique-value "foo"))
(displayln foo)

```

---

<div class="post-metadata">

### Author: ![gus-massa](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/gus-massa/32/507_2.png) [@gus-massa](https://racket.discourse.group/u/gus-massa)
#### Post date: [June 27, 2022, 1:55am UTC](https://racket.discourse.group/t/function-and-macro-to-define-unique-values/1097/9 "2022-06-27T01:55:19Z")

</div>

In case you don't want the number in the name, instead of `gensym` you can use `string->uninterned-symbol`

```scheme
#lang racket/base
(define f1 (string->uninterned-symbol "foo"))
(define f2 (string->uninterned-symbol "foo"))
f1 ; ==> 'foo
f2 ; ==> 'foo
(eq? f1 f2) ; ==> #f

```

---

<div class="post-metadata">

### Author: ![sschwarzer](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/sschwarzer/32/1940_2.png) [@sschwarzer](https://racket.discourse.group/u/sschwarzer)
#### Post date: [June 27, 2022, 5:29am UTC](https://racket.discourse.group/t/function-and-macro-to-define-unique-values/1097/10 "2022-06-27T05:29:33Z")

</div>

> [@gus-massa](#):
>
> Why don't you store the name inside the struct?

Good point.

Because I was so focused on the origin

```scheme
(struct unique-value ())

```

that I forgot to check the code for your change later. 😉 The custom write method came later after the functionality was in place. When I look at my code now, your suggestion looks obvious. 🙂
