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

From: Sam Tobin-Hochstadt (samth at ccs.neu.edu)
Date: Tue Jul 3 11:05:52 EDT 2012

On Mon, Jul 2, 2012 at 9:07 AM, Matthew Flatt <mflatt at cs.utah.edu> wrote:
> Thoughts so far:
> I think you need a new communication channel to get information from
> the expansion of an enclosing module to the expansion of its submodule.
> Expansion-time state is the right kind of channel, but I think it's
> important to start every submodule's expansion in a fresh store, at
> least usually. Otherwise, many syntactic extensions won't work
> correctly in a submodule.
> To give the programmer more control, we could add a
> `local-expand-submodule' function that is like `local-expand', but (1)
> it works only for `module' and `module*' forms in a 'module context,
> and (2) it accepts module paths to attach from the current expansion
> context to the submodule's expansion context.
> Using this addition, when expanding a `(module* name #f ....)'
> submodule, Typed Racket could attach a compile-time module that houses
> the "in a typed context" flag --- the same one that Typed Racket's
> `#%module-begin' sets. Does it sound like that would work?

I believe that this would work, and I'll use it if it's provided.

However, I don't (yet) think it's the right solution.  In particular,
I feel like this moves away from the really great feature of
submodules, which is that they behave basically exactly like regular
modules.  From what I can tell, the only place where this uniformity
breaks down currently is with `(module* name #f ....)', where the
outer module is `require`d *before* the inner module starts expanding.
 In other words, if we have:

(module M L
   (module* N #f ...))

currently `M` is required *before* `N` begins expanding, which is
unlike any other module relationship that can be expressed in Racket
(I think).  You said in your earlier mail that you don't think it
makes sense to change this ordering.  Can you expand on the reasons

> I worry that `local-expand-submodule' might be used to break a
> syntactic form by attaching a module that isn't intended to be attached
> to multiple expansion stores. I think a macro that abuses
> `local-expand-submodule' could only harm itself or some other module
> that trusts the macro, but it's difficult to be sure.
> At Mon, 25 Jun 2012 16:47:36 -0600, Matthew Flatt wrote:
>> At Mon, 25 Jun 2012 17:50:27 -0400, Sam Tobin-Hochstadt wrote:
>> > The problem (I
>> > think) is that the implicit `require` of `(submod "..")` happens
>> > *before* the expansion of `#%module-begin` inside the submodule.
>> That's the same for a top-level module M whose initial language is some
>> other module L, right? The require of `L' happens before the
>> `#%module-begin' expansion in `M'... and it can't be any other way,
>> because `#%module-begin' comes from `L'.
>> > The
>> > key bit of code is the residual snippet left in the outer module:
>> >
>> >          (begin-for-syntax
>> >              (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
>> > here.
>> I see what you mean, but I don't think it makes sense to change the
>> order of things in the way that you're suggesting. I don't have any
>> immediate ideas, but I'll think about it more.
>> _________________________
>>   Racket Developers list:
>>   http://lists.racket-lang.org/dev

sam th
samth at ccs.neu.edu

Posted on the dev mailing list.