This is the mail archive of the kawa@sources.redhat.com mailing list for the Kawa project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Module expressions (was Re: define-alias not being exported)


Per, thanks again.

Regarding the renaming of module exports, I wonder whether define-alias is
the best way to do it. 

One of the big problems with the module systems of languages like Kawa
(and many others - please understand that I am _not_ attacking Kawa,
except inasmuch as it inherits from a flawed tradition) is that they
regard modules as independent chunks of source code that must be compiled
independently into executables (in the most general sense, including JVM
code) and only then combined with one another. The same happens in Ada, in
the Prolog standard, in the use of Java classes as that language's nearest
equivalent to modules, and in many other languages.

Much better is to see modules as primitives in an expression in a "Module
Algebra". Just as the primitives in arithmetic are numbers, and the
operations are functions from numbers to numbers, so the primitives in
Module Algebra are modules, and the operations are functions from modules
to modules.

One consequence is that we can have a module-level rename.

For an example, let's assume that I needed to implement mappings in Kawa,
and that because I'm lazy and can't be bothered to optimise, I've done so
by encapsulating the alist operations in a module named Maps:
  (module-name 'Maps)

  (define-simple-class <map> () (pairs type: <list>) )

  (define (make-map #!rest args)
    (make <map> pairs: args)
  )

  (define (map-lookup (mapp <map>) key) <object>
    (assq key (slot-ref mapp 'pairs))
  )

  ...and so on...

  (map-lookup (make-map '( (one . 1) (two . 2) ) 'one)

  ...

So my functions make-map, map-lookup and so on work, albeit slowly, and I
use them in my prototype. 

Then I discover a more efficient Scheme package for maps, such as Stephen
Adams's Wttree, resident at
http://ftp.cs.indiana.edu/pub/scheme-repository/code/struct/wttree.txt .

I decide that I want to use this instead. But, a lot of my code now
calls Maps, and I want to keep the interface with it intact.

Now, I could dive into my Maps module and replace all the function bodies
by calls to wttree, then recompile it. That's treating the module as an
isolated chunk of code that gets compiled into an executable. After you've
compiled it, you can't do anything useful with it (such as renaming its
exports), because it's not any longer something represented in a way that
tells you about its origins, but merely something you can execute.

But suppose instead that we had an evaluator for module expressions. I
could then write something like
  module Maps = module Wttree * 
                rename { <wt-tree> |-> <map>,
                         alist->wt-tree |-> make-map,
                         wt-tree? |-> map?, 
                         wt-tree/lookup |-> map-lookup
                       } 
(In case it's not clear, the {} brackets are intended to represent a
function from the old names in Wttree to the new names in Maps. {} are set
brackets, and A|->B denotes a renaming of A to B.)

I suppose the more Schemely syntax would be
  (define-module 'Maps
                 (module-rename 'Wttree
                                '( ( <wt-tree> . <map> )
                                   ( alist->wt-tree . make-map )
                                   ( wt-tree? . map? )
                                   ( wt-tree/lookup . map-lookup )
                                 )
                 )
  )

If the lexemes in the names were consistent, we might even be able to
abbreviate as
  (define-module 'Maps
                 (module-rename 'Wttree
                                wt-tree map
                 )
  )
Wouldn't the saving in faded keytops and flattened fingertips be worth a
few beers to whoever implemented this? Plus, since we're writing less new
code, it really reduces load on the old CVS.

What's going on here is that the module-expression-evaluator starts with
the _source_ of each module, evaluates operations such as module-rename on
those, and only then compiles. That way, you keep _all_ the source level
information until you need it. You don't have this weird notion of
compiling first, and then trying to glue the resulting amorphous and
uninformative lumps of stuff together.

These ideas, I believe, originated with the algebraic specification
people, not least Joseph Goguen, see the references at
http://www.cs.ucsd.edu/users/goguen/sys/obj.html . Though you need to be
using an algebraic specification language such as CafeOBJ to use them to
best advantage, they can be applied to conventional languages. To quote
from the above:

  All recent OBJ languages provide parameterized programming, with  
  parameterized modules, module instantiation, views, module expressions,
  etc., to support very flexible program structuring and reuse; see An
  Implementation-Oriented Semantics for Module Composition, by Joseph
  Goguen and Will Tracz for much more information about parameterized
  programming and software reuse, including a description of a module
  composition system for Ada called Lileanna. 

A good reference that would apply to Kawa is via the link "An
Implementation-Oriented Semantics for Module Composition". It has been
used for Ada.

Jocelyn Paine
http://www.ifs.org.uk/~popx/
+44 (0)7768 534 091 

"Fry yer rabbit and yer shallots in the same pan. Yer fry 'em separate and
mix 'em arterwards, that don't taste 'arf so good."


On Sat, 28 Sep 2002, Per Bothner wrote:

> My recent check-in fixes this problem.
> 
> There are still problems with the implementation of define-alias,
> but at least there are improvements.  (My goal is to be able to
> use define-alias for renaming of module exports, but it isn't
> quite up to that yet.)
> -- 
> 	--Per Bothner
> per@bothner.com   http://www.bothner.com/per/
> 
> 


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