When should I use syntax/loc instead of #' (aka syntax)?
racket
Solution
Use `#'` (i.e. `syntax`) when you are not constructing a new syntax object, as when you're just referencing a pattern variable bound with `syntax-case` or `with-syntax`.
Use `#'` for temporary syntax objects as in `(syntax->list #'(id ...))`.
Use `#'` for syntax objects representing forms that you know won't have syntax errors in them, or where syntax errors in them are the fault of your macro implementation, not the use of your macro.
Use `syntax/loc` when you construct expressions that potentially can contain syntax-errors due to an incorrect usage of your macro.
Let's consider a concrete example:
The form `display-let` should work exactly like normal `let`, except that it displays the values of the bindings before it evaluates the body.
Here is a first implementation:
(define-syntax (display-let-1 stx)
(syntax-case stx ()
[(_ ([id expr] ...) body ...)
#'((lambda (id ...)
(displayln (format "~a is bound to ~a" 'id id)) ...
body ...)
expr ...)]))
Here is an example of a correct use of the macro:
> (display-let-1 ([x 1] [y 2]) (+ x y))
x is bound to 1
y is bound to 2
3
Now let us see what happens when the macro is used incorrectly:
> (display-let-1 ())
lambda: bad syntax in: (lambda ())
This usage is incorrect, since a use of `let` must always have a non-empty body. Besides printing the error message, DrRacket colors this code red:
(lambda (id ...)
(displayln (format "~a is bound to ~a" 'id id)) ...
body ...)
Although it is correct that the `lambda` expression constructed by the macro is incorrect, `(lambda ())` is not legal, it is not due to an error in the macro, but due to an incorrect use of the macro.
To redirect the blame surround the constructed `lambda` expression with `syntax/loc` and use the first argument of `syntax/loc` as place to color red.
(define-syntax (display-let-2 stx)
(syntax-case stx ()
[(display-let ([id expr] ...) body ...)
#`(#,(syntax/loc stx (lambda (id ...) body ...)) expr ...)]))
> (display-let-2 ())
display-let-2: bad syntax in: (display-let-2 ())
This time around the `(display-let-2 ())` entered in the repl is colored red, and the error message mentioned `display-let-2` instead of `lambda`.
Problem
A new syntax object can be constructed by both `syntax/loc` and `syntax` (also written `#'`). When should I use `syntax/loc`?