[racket] `namespace-set-variable-value!` doesn't "shadow"? How to do?

From: Greg Hendershott (greghendershott at gmail.com)
Date: Sun Nov 24 14:46:03 EST 2013

The code below is from
https://github.com/greghendershott/frog/blob/f9bda203b4b26d8f24bc466db93979a015873512/frog/template.rkt

As the comment indicate, I'd don't fully understand WTH I'm doing
here, except that it has worked fine so far.

However: One of the "template variables" I would like to supply is
named `date`, with a string value.

I expected that `namespace-set-variable-value!` would "shadow" the
`date` from racket/base. But it's not: Using @date in the template
gives an error that it can't convert the procedure to a string. So
clearly it's getting the string.

Things I've tried that don't help:

- Using `(namespace-undefine-variable! 'date template-namespace)`
first. It errors "namespace-undefine-variable!: given name is not
defined".

- Using `(namespace-undefine-variable! 'date (current-namespace))`
first. Same error.

- Supplying #t instead of #f for the `map?` argument of
`namespace-set-variable-value!`.

- Using `(require (except-in racket/base date))` for the template.rkt
-- figuring it was sneaking in via the original namespace. Although
that compiles fine, `date` is still defined in `template.rkt`.  So
perhaps my "sneaking in" theory is right, but -- how can I keep it out
of template.rkt in the first place?

So:

1. Is there a way to make `namespace-set-variable-value!` "shadow", generally?

2. If not, how can I at least shadow a specific symbol, such as `date`?


- - - template.rkt - - -

#lang racket/base

(require racket/dict
         racket/contract
         web-server/templates
         frog/widgets)

(provide render-template)

;; Beware, cargo cults be here!
;;
;; The idea here is that we make some variables visible in the
;; namespace in which the template is evaluated. Some of these are the
;; variables and values explicitly passed to us in `dict`. The others
;; are from the modules web-server/templates and frog/widgets.
;;
;; Now, web-server/templates are normally used "statically" --
;; compiled into the web-server application. However it's also
;; possible to use them "dynamically" -- to load and use one at run
;; time.
;;
;; I wish I had a crisper understanding how and why the following
;; works, but it does, following this Racket mailing list thread:
;; http://www.mail-archive.com/users@racket-lang.org/msg18108.html

(define/contract (render-template dir filename dict)
  (path? path-string? dict? . -> . string?)
  (define template-namespace (make-empty-namespace))
  (define (attach/require m) ; symbol? -> void
    (namespace-attach-module (current-namespace) m template-namespace)
    (parameterize [(current-namespace template-namespace)]
      (namespace-require m)))
  (attach/require 'web-server/templates)
  (attach/require 'frog/widgets)
  (for ([(k v) (in-dict dict)])
    (namespace-set-variable-value! k v #f template-namespace))
  (define to-eval
    #`(include-template #,(datum->syntax #'render-template filename)))
  (parameterize ([current-directory dir])
    (eval to-eval template-namespace)))

Posted on the users mailing list.