[racket-dev] Trouble with state, submodules, and module-begin

From: Sam Tobin-Hochstadt (samth at ccs.neu.edu)
Date: Mon Jun 25 17:50:27 EDT 2012

On Mon, Jun 25, 2012 at 5:38 PM, Matthew Flatt <mflatt at cs.utah.edu> wrote:
> I think I misunderstood your complaint. If you change the example to
>  (module+ sub
>    (#%module-begin (m)))
> then there's no error. So, I think you're running into the old
> only-form-in-module-just-might-expand-to-#%module-begin problem.

Sorry, that was a confusing red herring on my part.  I now think I
understand what's going wrong.  I've revised the gist to be a more
complete representation of what's going on in TR.  The problem (I
think) is that the implicit `require` of `(submod "..")` happens
*before* the expansion of `#%module-begin` inside the submodule.  The
key bit of code is the residual snippet left in the outer module:

             (when (unbox is-typed?)
               (set-box! type-env 1)))

Currently, in TR, the code in the begin-for-syntax is unconditional,
and therefore it gets re-run in the store used for expanding the inner
submodule.  However, if I add the `when`, then the `set-box!` doesn't
happen, and the expansion of `m` fails.  I'd like to be able to add
this conditional, so I'd like to change the order of effects slightly

> The usual solution is form `m' to check whether it's being expanded in
> a 'module-begin context, in which case it should wrap itself in
> `begin', or something like that.
> At Mon, 25 Jun 2012 17:28:23 -0400, Sam Tobin-Hochstadt wrote:
>> On Mon, Jun 25, 2012 at 5:14 PM, Matthew Flatt <mflatt at cs.utah.edu> wrote:
>> > The expansion of submodules is intended to have a fresh store, just
>> > like the expansion of any module. The `#f' initial import is intended
>> > to be something like using `(submod "..")' as the initial language,
>> > except importing all internal bindings of the module instead of its
>> > exports.
>> >
>> > Can Typed Racket not handle enclosing bindings in the same way that it
>> > handles `require's in general?
>> Currently, it can.  However, I wanted to make a fairly small change to
>> only update the type environment when needed, and it broke because of
>> this.  In the context of my example, the `(m)` invocation is expanded
>> *before* the inner `#%module-begin` expansion happens, meaning that it
>> hits the error case, even though it's expanded inside a module with
>> the appropriate `#%module-begin` binding.
>> With submodules as they currently work, the inner `#%module-begin` is
>> expanded quite late, which I think breaks other possible expectations
>> about #%module-begin as well.  Moving it earlier will, I think,
>> alleviate all of these issues.
>> >
>> > At Mon, 25 Jun 2012 17:05:21 -0400, Sam Tobin-Hochstadt wrote:
>> >> It appears that the expansion of (module* m #f ...) occurs in a fresh
>> >> store, but before running the inner module's `#%module-begin` binding.
>> >> To see this, run the program at https://gist.github.com/2991214 , and
>> >> note that ">> in module-begin" is printed only once, but the expansion
>> >> of `m` fails, indicating a fresh store.
>> >>
>> >> This is troublesome for Typed Racket, which uses the store to record
>> >> the types of identifiers. Is this the intended behavior?
>> >> --
>> >> sam th
>> >> samth at ccs.neu.edu
>> --
>> sam th
>> samth at ccs.neu.edu

sam th
samth at ccs.neu.edu

Posted on the dev mailing list.