[plt-scheme] Questions about modules in embedded system
I am trying to embed PLT Scheme in an OS X program, so I can write the
guts of my application in portable Scheme and do the GUI frontend using
native OS X tools. I want to abstract the GUI frontend (the view and
controller) from the scheme backend (the model) as cleanly as possible,
to make it easier to write new frontends for other platforms. I am
having some trouble understanding the module system.
My plan was to keep the Scheme guts in a private collects tree shipped
with the application, with a module called "backend" that provides all
of the definitions that the GUI uses. Then, I wanted to have a second
module "frontend" defined by the GUI that provides all of the
definitions used by Scheme code to manipulate the GUI.
Question one: Some of the primitives in "frontend" close over GUI
object handles that aren't known until fairly late in the GUI's life
(awakeFromNib:). Moreover, they are registered in many different
places, from the constructors of the GUI objects they close over. But
primitive modules must be completely defined
(scheme_finish_primitive_module) before they can be used, and anyway,
the compiler needs a definitive list of "frontend" exports at build
time. My workaround is to define a regular module called "frontend" in
the collects tree, with a bunch of lines like (define entry1
entry-unbound) that reserve a slot for every primitive that might get
loaded, and have the GUI fill in these slots as objects are
constructed. Is there a better way to register primitives for the
Scheme code to call, when the primitives and the objects they close
over aren't all known before the Scheme code starts running?
Question two: Given that (require (lib "backend.ss" "app")) has been
called in the initial namespace, how do I (from C) get the value of an
symbol X such as eval would do when evaluating (f x)?
scheme_lookup_global doesn't seem to work for imports -- because it
only searches the binding list, not the import list? I need to do this
to resolve the actual entrypoints so I can apply() them.
Question three: How can I (from C) set! the value of a variable bound
to X in (lib ("frontend.ss" "app"))? My current workaround is to expose
a function (through "backend") that is defined in "frontend" which
takes the variable X to set in "frontend" and its new value. Do I need
to use scheme_module_bucket and change a field of the bucket returned?
How do I get the first argument to scheme_module_bucket? My best guess
is that it's a symbol that is listed in the "module registry" as
mapping to a module declaration (the result of compiling (module ..)?)
-- and then this is mapped to a module instance somehow? Would this
symbol be 'frontend? Then how is the module registry managed to avoid
conflicts between (lib "foo.ss" "111") and (lib "foo.ss" "222")? I am
thinking that current-module-name-prefix is involved but I can't quite
work out how it works.
Also: when distributing an application such as this, you'd like to ship
a self-contained system (no system collects tree required) but you'd
like to minimize the size of your program. Is there an easy way to
figure out what parts of the system collections are used by your code,
so you can ship only those? If I wrote a script to do so, say by
walking the module tree, any reason I couldn't just concatenate all of
the referenced source files in load order and compile them into a
single .zo and (load) that -- assuming I transformed the names to not
collide, and wrote a custom module name resolver to map (lib ...) into
a transformed name?
And what does the --embedded option to mzc do? I can't find it in the
documentation.
Thanks for the great software, and thanks in advance for any help --
Geoff Schmidt