# Syntax parameter encapsulation

**URL:** <https://racket.discourse.group/t/syntax-parameter-encapsulation/2119>\
**Category:** General\
**Tags:** macro\
**Created:** [July 20, 2023, 1:20am UTC](https://racket.discourse.group/t/syntax-parameter-encapsulation/2119 "2023-07-20T01:20:07Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![notjack](https://avatars.discourse-cdn.com/v4/letter/n/e47774/32.png) [@notjack](https://racket.discourse.group/u/notjack)\
**Post date:** [July 20, 2023, 1:20am UTC](https://racket.discourse.group/t/syntax-parameter-encapsulation/2119/1 "2023-07-20T01:20:07Z")

</div>

For a long time now, when I've wanted an "anaphoric macro" I've used syntax parameters. Consider a library that defines a `define/return` macro for defining functions that can be short circuited using `return`. The way I'd normally implement that is like this:

```scheme
(provide define/return
         return)

(define-syntax-parameter return
  (λ (stx)
    (raise-syntax-error 'return "must be used inside define/return" stx)))

(define-syntax-parse-rule (define/return header:expr body:expr ...+)
  (define header
    (let/ec escape
      (syntax-parameterize ([return (make-rename-transformer #'escape)])
        body ...))))

```

This works, but it means that `return` is exposed _as a syntax parameter_ to clients of the library. Someone could do this:

```scheme
(require "my-awesome-return-library.rkt")

(define (explode)
  (error "everything exploded"))

(define/return (foo)
  (syntax-parameterize ([return (make-rename-transformer #'explode)])
    (return)))

```

This fails with the error `everything exploded`, which is a bit weird. I'm not sure clients should be allowed to redefine `return` out from under themselves like that.

The `define/return` library can put in a little work to prevent this however. The key lies in the observation that only the _state_ passed from `define/return` to `return` needs to be a syntax parameter, not the entire `return` form. So the library could do this:

```scheme
(provide define/return
         return)

(define-syntax-parameter return-continuation #false)

(define-syntax-parse-rule (return expr:expr ...)
  #:fail-unless (syntax-parameter-value #'return-continuation)
  "must be used inside define/return"
  #:with escape (syntax-parameter-value #'return-continuation)
  (escape expr ...))

(define-syntax-parse-rule (define/return header:expr body:expr ...+)
  (define header
    (let/ec escape
      (syntax-parameterize ([return-continuation #'escape])
        body ...))))

```

And now clients can't redefine `return`. The syntax parameter used to communicate between `define/return` and `return` is fully encapsulated.

Lately I've come around to believing that this is a Good Idea™ and maybe even a Best Practice™. Does anyone else do this?

---

<div class="post-metadata">

**Author:** ![sorawee](https://avatars.discourse-cdn.com/v4/letter/s/ea5d25/32.png) [@sorawee](https://racket.discourse.group/u/sorawee)\
**Post date:** [July 20, 2023, 1:40am UTC](https://racket.discourse.group/t/syntax-parameter-encapsulation/2119/2 "2023-07-20T01:40:53Z")

</div>

What do you think about the following code? Should it fail?

```scheme
(define/return (foo)
  (let ([return explode])
    (return)))

```

---

<div class="post-metadata">

**Author:** ![notjack](https://avatars.discourse-cdn.com/v4/letter/n/e47774/32.png) [@notjack](https://racket.discourse.group/u/notjack)\
**Post date:** [July 20, 2023, 1:52am UTC](https://racket.discourse.group/t/syntax-parameter-encapsulation/2119/3 "2023-07-20T01:52:15Z")

</div>

That ought to explode, but in the same way it would if you used any other form name. It's just ordinary lexical scoping:

```scheme
(define (foo)
  (let ([define explode])
    (define)))

```

The reason syntax parameters are particularly dangerous is that people can write macros on top of them that are affected by parameterization, like this:

```scheme
(define-syntax-parse-rule (return-when condition:expr)
  (when condition
    (return)))

(define/return (foo)
  (return-when (should-return?))
  (displayln "foo"))

```

In that case, reparameterizing `return` will change the behavior of `return-when`. In the case of more complex macros, that can cause weird and confusing breakages. This breakage doesn't occur with a simple `let`-based shadowing of `return`.

---

<div class="post-metadata">

**Author:** ![EmEf](https://avatars.discourse-cdn.com/v4/letter/e/53a042/32.png) [@EmEf](https://racket.discourse.group/u/EmEf)\
**Post date:** [July 20, 2023, 12:34pm UTC](https://racket.discourse.group/t/syntax-parameter-encapsulation/2119/4 "2023-07-20T12:34:56Z")

</div>

Arguably also a ‘feature’:

```plaintext
(module client racket

  (provide foo)

  (require (except-in (submod ".." my-awesome-return-library) return))
  (require [rename-in (submod ".." my-awesome-return-library) [return return0]])
  (require racket/stxparam)
  
  (define-syntax-parameter return
    (λ (stx)
      (raise-syntax-error 'return "must be used inside define/return" stx)))
  
  (define/return (foo)
    (syntax-parameterize ([return (λ (stx) (syntax-case stx () [(_ x) #'(return0 (begin (eprintf "log ~a\n" x) x))]))])
      (return 1))))

(require 'client)

[foo]

```

Obscure but I bet you have thought of this too. — Matthias

---

<div class="post-metadata">

**Author:** ![benknoble](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/benknoble/32/16_2.png) [@benknoble](https://racket.discourse.group/u/benknoble)\
**Post date:** [July 20, 2023, 1:34pm UTC](https://racket.discourse.group/t/syntax-parameter-encapsulation/2119/5 "2023-07-20T13:34:23Z")

</div>

Based on Matthias’s reply, I’d say it’s a question of what you want to expose: an extremely flexible but possibly dangerous or confusing interface, or a rigid but easier to use as intended interface? Different libraries or projects or people make different tradeoffs.

A middle option is to document `return` as syntax, not a syntax parameter, and if someone has problems when they `syntax-parameterize` it, well, they’re holding it wrong. They can if they want, but it’s not expected that the library supports whatever weird thing they’re doing.

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [July 20, 2023, 4:44pm UTC](https://racket.discourse.group/t/syntax-parameter-encapsulation/2119/6 "2023-07-20T16:44:58Z")

</div>

Apropos variations of syntax parameters:  
[https://docs.racket-lang.org/syntax-implicits/index.html](https://docs.racket-lang.org/syntax-implicits/index.html)
