In the context of writing Racket macros, what does "3D syntax" mean?
I've heard the phrase a few times. Including once in reference to a macro I was writing. But that was awhile ago; I fixed it, and now I can't remember exactly what I was doing wrong originally.
Also: Is 3D syntax always bad? Or is it like eval
(where if you think you need to use it, you're probably wrong, but there are some valid uses in expert hands)?
Syntax objects are usually supposed to be just serializable data. 3D-syntax weakens this condition: it allows us to sneak in arbitrary values, and not just plain data. That's what makes them "3d": they are values that rise above the regular flat things you'd expect out of syntax objects.
For example, we can sneak in lambda
values!
#lang racket
(define ns (make-base-namespace))
(define (set-next! n)
(parameterize ([current-namespace ns])
(eval #`(define next #,n)))) ;; <-- 3d-syntax here
(define (compute s)
(parameterize ([current-namespace ns])
(eval s)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define counter 0)
(set-next! (lambda ()
(set! counter (add1 counter))
counter))
(compute '(+ (next)
(next)
(next)
(next)))
Doing this is usually a bad thing, because the presence of such values probably means an ill-founded attempt to leak information across phases of compilation. The result is something that's likely not separately-compilable. If you see an error that sounds something like:
write: cannot marshal value that is embedded in compiled code value
then that is most likely due to a macro having produced a piece of 3d-syntax that can't be serialized to bytecode.
Sometimes, in rare situations, we really do want 3d-syntax, often in dynamic evaluation contexts. As a concrete example, a debugger in DrRacket may want to annotate the syntax of a program so that function applications directly call back into functions of the debugger, so that we can do things like interactive code coverage coloring in the program editor. In that sense, 3d-syntax can act as a communication channel between dynamically-evaluated code and its ambient environment.