[racket] Confused about submodule + state

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Sat Apr 12 17:43:19 EDT 2014

Yes, that's the intended behavior.

Possibly, you're expecting

 (require (submod "test.rkt" sub))

to instantiate the submodule at phase 1, since the module was declared
at phase level 1 relative to its enclosing module. But the declaration
phase level doesn't matter for `require`; it instantiates the `sub`
module at phase 0.

Since `sub` lives at phase level 1 relative to the enclosing module,
the enclosing module lives at phase level -1 relative to the `sub`
module. So

 (require (submod "test.rkt" sub))

uses a phase 0 variable `tbl`: that's +1 (due to `begin-for-syntax`)
plus -1 (relative to the submodule).

The `print` macro imported with `(require "test.rkt")` accesses a `tbl`
variable that lives at phase 1. So, that's why the `print` module
doesn't see any changes to the phase 0 `tbl` that `sub` mutates.

If you import `(submod "test.rkt" sub)` with `for-syntax`, then `sub`
is instantiated at phase 1, and it shares the phase 1 `tbl` with a
plain import of "test.rkt":

 > (require "test.rkt")
 > (print)
 #<syntax:/tmp/test.rkt:11:32 x> -> outer
 > (require (for-syntax (submod "test.rkt" sub)))
 #<syntax:/tmp/test.rkt:11:32 x> -> outer
 #<syntax:/tmp/test.rkt:11:32 x> -> inner
 > (print)
 #<syntax:/tmp/test.rkt:11:32 x> -> inner


At Sat, 12 Apr 2014 16:56:24 -0400, Asumu Takikawa wrote:
> Hi all,
> 
> I'm trying to figure out how submodules and compile-time state interact,
> in particular when the submodule is in a `begin-for-syntax`.
> 
> Example: https://gist.github.com/takikawa/10555205 (also inlined below)
> 
> As the interaction shows, the submodule can read the compile-time table
> but when it tries to modify it, the modifications only appear to be
> visible from the submodule and not the outer module.
> 
> Is that the expected behavior? Should I not rely on side effects
> persisting between a submodule and its containing module?
> 
> Cheers,
> Asumu
> 
> ;;;
> 
> #lang racket
> 
> (require (for-syntax racket/dict syntax/id-table))
> 
> ;; track stuff in this table
> (begin-for-syntax
>   (define tbl (make-free-id-table)))
> 
> ;; a binding we can use in the table
> (define x 3)
> (begin-for-syntax (define q-x #'x))
> 
> (begin-for-syntax
>   ;; initially set x -> "outer"
>   (dict-set! tbl q-x "outer")
> 
>   (module* sub #f
>     ;; the submodule sees "outer"
>     (for ([(k v) (in-dict tbl)])
>       (printf "~a -> ~a~n" k v))
>     (dict-set! tbl q-x "inner")
>     ;; the submodule now sees "inner"
>     (for ([(k v) (in-dict tbl)])
>       (printf "~a -> ~a~n" k v))))
> 
> ;; this macro just prints what's in the table
> (define-syntax (print stx)
>   (syntax-case stx ()
>     [(_)
>      (for ([(k v) (in-dict tbl)])
>        (printf "~a -> ~a~n" k v))
>      #'(void)]))
> 
> (provide print)
> 
> ;;;
> 
> $ racket
> Welcome to Racket v6.0.1.1.
> -> (require "test.rkt")
> -> (print)
> #<syntax:/tmp/test.rkt:11:32 x> -> outer
> -> (require (submod "test.rkt" sub))
> #<syntax:/tmp/test.rkt:11:32 x> -> outer
> #<syntax:/tmp/test.rkt:11:32 x> -> inner
> -> (print)
> #<syntax:/tmp/test.rkt:11:32 x> -> outer
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users

Posted on the users mailing list.