[plt-scheme] Reloading code
Curt Ferguson wrote:
> Hi all. I'm very new to scheme so I'm sure I'll have a number of
> questions. I'll try to phrase them intelligently and clearly.
>
> What I'm trying to do is create a program that is basically an event
> loop. It will read in various modules and then start the loop, the loop
> will perform various processing tasks and look for user input, without
> any input it will run various tasks again and look for input...etc.
>
> What I need is for a user to input a command and have the program reload
> parts of the program code, not necessarily all of it. Probably
> individual modules. I don't know if it would be possible for an
> internal command to reload individual procedures. Purpose being if/when
> a source file is modified on disk, I want the user (who won't have
> access to the machine shell) to be able to reload just the modified
> portion of the code. Or as small a section as possible that includes
> the modified section, such as a module perhaps.
>
> I know this is probably an extended topic to get answered by mail, so
> what I'm asking the list for is your reference links that might be
> pertinent... Snippets, examples, modules, etc, that would show me
> things like this. (Or any examples of reloading code at all).
It's possible to re-declare modules. If those modules are participating
in a program (that is, they've been invoked), then when you redeclare
the module, the new version is invoked and its exports override the
previous exports. For this to happen, you'll need to set the
'compile-enforce-module-constants' parameter to #f before you load any
module that you may eventually want to reload. See the section of the
reference on "Module Re-declarations".
One main caveat (among several caveats I could list): If you reload a
module that declares structs, then you'll generate entirely new
structure types and you'll redefine the names of the constructors,
predicates, and accessors to work only on the new versions. If you have
instances of the old structure types floating around, things will get weird.
Consider whether you really want to reload modules the way you
described. You might be able to get what you want by setting up your
code to use parameters or boxes or whatnot and updating those when you
want to change the behavior of your program.
**
Here's the rough path of control in the normal loading of modules:
'require' (or 'dynamic-require')
-> the module name resolver (see 'current-module-name-resolver')
-> the loader (see 'current-load')
-> the evaluator (see 'current-eval')
For a module to be invoked (required), it must first be declared. The
module name resolver is responsible for loading module declarations on
demand from the filesystem. The module name resolver keeps a table of
modules that have been loaded. It only loads the declaration the first
time around; subsequent requests for the module just get the existing
declaration, even if the file has changed.
What you want to do is to bypass the module name resolver and reload the
module declarations directly. To do this, though, you need to use some
of the same machinery as the module name resolver to make sure you're
redeclaring the right thing. The section on "Module Names and Loading"
seems to be the best reference for this.
Here's some code that should give you a starting point. The reloading
capabilities are in the "manager.ss" module. It uses 'dynamic-require'
to start off the managed program, which consists of "value.ss" and
"print.ss".
;; manager.ss
#lang scheme/base
(provide reload
go)
(compile-enforce-module-constants #f)
(define (reload x)
(let ([resolved-x ((current-module-name-resolver) x #f #f #f)])
(parameterize ((current-module-declare-name resolved-x))
(load/use-compiled (resolved-module-path-name resolved-x)))))
(define go (dynamic-require "print.ss" 'print-the-value))
;; end of manager.ss
;; print.ss
#lang scheme/base
(require "value.ss")
(provide print-the-value)
(define (print-the-value)
(printf "~a\n" the-value))
;; end of print.ss
;; value.ss
#lang scheme/base
(provide the-value)
(define the-value 'apple)
;; end of value.ss
Then:
> (require "manager.ss")
> (go)
apple
Now edit "value.ss" and change 'apple' to 'orange'.
> (reload "value.ss")
> (go)
orange
Hope that helps,
Ryan
> _________________________________________________
> For list-related administrative tasks:
> http://list.cs.brown.edu/mailman/listinfo/plt-scheme