This is the mail archive of the guile@cygnus.com mailing list for the Guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Where should guile modules store meta data?


[please excuse the delay]
David Lutterkort <lutter@cise.ufl.edu> writes:


> (defmacro* define-module (name #&key import export . rest)
>   (let ((body (remove-keywords rest)))
>     `(let ((new-module (make-new-module)))
> 	(register-module ',name new-module) 
> 	(module-resolve-imports new-module ',import)
> 	(module-make-public-interface new-module ',export)
> 	(eval (begin ,@body) (module-eval-environment new-module))
> 	new-module)))

In other words:

1. create a generic module <new-module>---in which environment!?!
2. restrict the type  of <new-module> to (im-/export)
3. evaluate its body in the environment of <new-module>

The problem: In which environment should (define-module...) be
evaluated?  If it is evaluated in the current module, you can't share
this module with others because it (logically) belongs to the current
module.

This is why Jonathan Rees has created a special config environment
where all modules live:

> ,config  ; leave the scheme world and enter a meta world to create 
           ; a new module
config> (define-structure A (export c) (open scheme) (begin (define a 12) (define (b) (display a))))
config> a
'#{Structure 116 a}
config> scheme
'#{Structure 56 scheme}
config> (define x 99)
config> x
99
config>,in a  ; enter the scheme world (module a)
a> a
12

Note that structures are created in a separate environment ("world").
He uses a configuration language (which is scheme of course) to
create and modify structures ("modules").


What is wrong with the (define-module ..) syntax above?  

"A module is a structure used to encapsulate related data and
functions with a restricted view from the outside."  But does this
mean that a module is part of the system it structures?  Is a module a
first class object?

A module can't be a first class object because it describes the physical
view of the system.  When you look at a system from the outside, you
see modules.  But if you step inside the system you can see other modules,
but these modules tradidionally have a differend name: "classes".

In other words a module structures a system physically while a class
structures a system logically.  I think we should not mix these two
(related) concepts.

This means that you can't *define* a module at runtime.  If your
computer crashes, the module is gone.  What you can do is to create a
module and register it in some kind of secondary repository, but it is
impossible to *define* a new module within guile.  (In scheme48 the
primary module repository is the config environment.)


(Don't take the following too serious)

The guile module repository
----------------------------

Guile modules are stored under $GUILE_LOAD_PATH/<module-name>.scm
For example: (org gnu guile ice-9 test) will be stored unter
$GUILE_LOAD_PATH/org/gnu/guile/ice-9/test.scm.

Guile uses two repositories.  One for modules stored in
the file system and one for in-memory modules created by
(create-module ...) and register_c_module() (?).



The configuration language:
---------------------------
(export <sig>)                -> unspecified  symbols must exist
(protect <sig>)               -> unspecified  symbols must exist
(open (<name>))               -> unspecified  module must exist in file <name>
(access <name>)               -> <module>     module must exist in file <name>
;(<module> symbol)            -> <value>      symbol must exist in module
(ref <module> symbol)         -> <value>      symbol must exist in module
(load <name>)                 -> unspecified  load code from file  file must exist
(the-module)                  -> <module>

-----
Special case for backward compatibility (used to create
old (define-module ...) syntax):

(module <name> optionals)     -> unspecified
checks if module <name> is the current module and does
nothing. :>

optionals:  (export <sig>)
            (protect <sig>)
            (open <name>)
            (begin <code>)
            (load <name>)

(see above)
-----


Creating new modules (in memory)
(create <name>)               -> <module>

Starting new repl in module
(go <module>)                 -> unspecified   new repl

Accessing environments:
(module-eval-environment <module>)   -> <eval-environment>



(module-ref <module> <ref-module> <sym>)             
syntax: (ref (the-module) <ref-module> sym)

(module-load <module> <name>)
syntax: (load (the-module) <name>)

(module-go <module> <go-module>)
syntax: (go (the-module) <go-module>)

(module-protect <module> protect-list)
syntax: (protect (the-module) protect-list)

(module-export <module> export-list)
syntax: (export (the-module) export-list)

(module-open <module> import-list)
syntax: (open (the-module) import-list)

(module-access <module> <name>)
syntax: (access (the-module) <name>)

(module-create <module> <name>)
syntax: (create (the-module) <name>)


Examples:

guile      > (define m (create (my test))) ; create a new module
guile      > (go m)                        ; start a new repl in m
my/test    > (the-module) -> #(#<eval environment> #f #f <useslist> ice-9/test5)
my/test    > (export (a b c))              ; set the export list
my/test    > (the-module) -> #(#<eval environment> #<export environment> #f <useslist> ice-9/test5)   
my/test    > (go (create (my test2)))      ; create and go to my/test2

my/test2   > (open ((my test) (ice-9 root)))
my/test2   > a -> #f                       ; from my/test (note: #f!)
my/test2   > (go (access (my test)))       ; go back to test

my/test    > (create (ice-9 test))         ; create a new module (not possible, module is in primary repository)
                -> error module exists but has not been loaded

my/test    > (go (access (ice-9 test)))    ; auto-load ice-9/test



> Here's one reason why it is good to have several modules in one file: I
> write a fairly large script that becomes much clearer if I split it up into
> several modules. 

You can structure them into classes instead and put these classes into
your module.  As in java. :>  As I said earlier if you want to structure
your software logically, use classes, if you want to structure it
physically, use modules.  This is why programming languages have both
modules *and* classes.


> high-level module system. I would really like to see an import-renaming
> facility added to the current module system ....

If you specify what import-renaming should do, I'll implement that.
Btw. that's where module and class concepts differ.  Modules use
selective import while classes import all features and then rename them:

; in module (ice-9 test20)
(define handle-of-root-module (access (ice-9 root)))
(define handle-of-my-module (access (ice-9 test1))
(handle-of-root-module a) -> 11
(handle-of-my-module a) -> 13
a -> 20

; in some module
(define-class (a (import) (export x) ((define x 99))))
(define-class (b (import) (export x) ((define x 100))))
(define-class (c (import a (rename x y)) (import b (rename x z))))
(c x) -> error
(c y) -> 99
(c z) -> 100

As you can see modules and classes are orthogonal.


Jost

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]