`__FILE__` and `__LINE__` in Racket
Many languages have a variable (or preprocessor macro) called __FILE__ or __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
__FILE__ends inmain.rkt; instead we’d use amainsubmodule(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?
Simply:
1 2 |
(syntax-source #'here) ;full path to the source file, i.e. __FILE__ (syntax-line #'here) ;line number, i.e. __LINE__ |
You could use #'0 or #'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 (syntax
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 0 or 42 or here or (+ 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 syntax-source and syntax-line.2
What if you want to write __FILE__ and __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 __FILE__ or __LINE__. So we’re careful to give that input stx to source-file or 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#'herea.k.a.(syntax here)is basically quoted data — like'herea.k.a.(quote here). We’re notevaluating the syntax. ↩