`__FILE__` and `__LINE__` in Racket
Many languages have a variable (or preprocessor macro) called
__file__ whose value is the pathname of the current source file. Likewise
__LINE__ for the the source line number.
You probably need this less in Racket than you imagine. For example:
We wouldn’t test that
main.rkt; instead we’d use a
(module+ main <your code here>).
To get a data file
foo.datlocated in the same directory as a source file we’d use
(define-runtime-path foo.dat "foo.dat"). If we’re a package or executable this works regardless of where our files happen to get installed.
But if you really did need a
__FILE__ in Racket, how would you do it?
(syntax-source #'here) ;full path to the source file, i.e. __FILE__ (syntax-line #'here) ;line number, i.e. __LINE__
You could use
#'42 instead. The only important thing about
#'here is that it’s a syntax object representing syntax from the current source file. The
#' prefix is what matters; it’s reader shorthand for the
syntax function. So
#'here is read as
here), which you could also use if you don’t mind typing a few more keys.
1 2 3
;; Same as above (syntax-source (syntax here)) ;full path to the source file, i.e. __FILE__ (syntax-line (syntax here)) ;line number, i.e. __LINE__
In some Lisps, a macro works on a plain s-expression — the
(+ 1 1). A syntax object in Racket contains the s-expression, and also information such as source location (line, column, position, span) and lexical scope.1
So in Racket, you simply need to make some syntax object in your source file, like
#'here, and feed it to syntax object accessors like
What if you want to write
__LINE__ like in other languages? You could define these as macros in a file, and
require and use where desired:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#lang racket/base (provide __FILE__ __LINE__) (require (for-syntax racket/base)) (define-syntax (__FILE__ stx) ;; `stx` comes from where the macro was invoked, so give _that_ to ;; `syntax-source`. (with-syntax ([file (syntax-source stx)]) (syntax-case stx () [_ #'file]))) (define-syntax (__LINE__ stx) ;; `stx` comes from where the macro was invoked, so give _that_ to ;; `syntax-line`. (with-syntax ([line (syntax-line stx)]) (syntax-case stx () [_ #'line])))
In this case, we care about the source file and line from where the macro was invoked — from where we typed
__LINE__. So we’re careful to give that input
source-line. (Whereas if we used some made-up syntax object literal like
#'here, it would give us the source or line of
#'here in the macro definition.)
It turns out that learning how to do a
__FILE__ in Racket ends up being a gentle, practical introduction to syntax objects.
For more about syntax objects see my Fear of Macros. Or if you’re coming to Racket from another Lisp, it might be quicker to read Eli Barzilay’s blog post. ↩
You might be wondering, why isn’t there an error that no identifier named
hereis defined? Great question. A syntax object such as
(syntax here)is basically quoted data — like
(quote here). We’re not
evaluating the syntax. ↩