[Grace-core] A module proposal

Eric Tanter etanter at dcc.uchile.cl
Wed Nov 30 06:13:25 PST 2011


Hi,

Just a light contribution to the discussion, wrt import/export. 
The Racket module system has very practical support for this.
See: 
http://docs.racket-lang.org/guide/modules.html

In particular imports and exports:
http://docs.racket-lang.org/guide/module-require.html
http://docs.racket-lang.org/guide/module-provide.html

The cool things include ways to import a module but renaming the imported elements (or just add a prefix), say that you export everything you defined except X and Y, rename/prefix your elements on export, etc.

In the case of Racket that scales especially well, including for linguistic abstractions (macros), so language extensions/restrictions can be defined using the exact same mechanisms.

Hope this helps, and sorry for the noise if that was already on your radar.

-- Éric


On Nov 3, 2011, at 3:33 PM, Kim Bruce wrote:

> The following proposal resulted from James' visit to Claremont.  It builds on his initial proposal, but I'm not sure how much he agrees with this proposal.  So, if you like it, we'll share the credit, and if you don't, I'll take the blame.
> 
> Kim
> 
> 
>  Proposal for Modules in Grace:
>  
> (This is long, so my apologies, but without the length it is hard to explain.  I can also post this to the blog if there is enough agreement on the general proposal.)
>  
> The first thing to note about this proposal is that there are still some pieces that are not yet determined.  The most important is probably what kind of a wrapper we want to put around a module.  It seems reasonable to give it a name, so that is all I did here.  On the other hand, we might want to introduce a key word “Module” or perhaps we want to wrap a module with “object” or “type”.  I didn’t want to decide here, so just mark the beginning with  “SomeModuleName” and end it with “end SomeModuleName” where “SomeModuleName” is the name of the module.  Better ideas are welcomed.
>  
> The key idea is that a module consists of a series of definitions or specifications of types, objects, and classes.  I’ve written all of this in the statically-typed dialect (subset?) of Grace, but I assume we can work out ways of making this useful in the dynamically-typed one.
>  
> Modules may only provide specifications for some objects.  For example, in the StackInterfaceModule given below, full definitions are given for the two types, but the object stackMaker is only provided with a declaration, with no value associated.  This makes it easier to have modules actually work “modularly” as different implementations can be provided.  We might want to mark some modules as “interface” modules (or perhaps use some other keyword) to indicate that they are incomplete.
>  
> Example of an interface module:
> 
> --------------------------------------------------------------
>  
> StackInterfaceModule:
> // might need some annotation to say this module leaves some things undefined
>  
> type Stack<T> = {
>     push(_:T) -> Unit
>     pop -> T
> }
>  
> type StackFactory = {
>    empty<T> -> Stack<T>
> }
>  
> def stackMaker: StackFactory
>  
> end StackInterfaceModule
>  
>  --------------------------------------------------------------
>  
> Next we provide a module which supplies the missing pieces for StackInterfaceModule.  We might want to say somewhere that this does supply the missing pieces for that interface module, but I left that out here.
>  
> This module imports the definitions in the interface and then provides StackClass (which is not mentioned in the interface), and the factory object, stackMaker.
>  
>  --------------------------------------------------------------
>  
> StackImplementationModule:
>  
> from StackInterfaceModule import Stack<T>, StackFactory
> // might need some way of annotating to make these definitions exported as well
>  
> class StackClass<T> implements Stack<T> {  // details omitted for brevity
>      var rep:… := …
>      method push(e:T) -> Unit {…}
>      method pop -> T {…}
> }
>  
> def stackMaker = object {
>    empty<T> -> Stack<T> {      // could call this new instead of empty
>         return StackClass<T>.new
>    }
> }
>  
> end StackImplementationModule
>  
>  --------------------------------------------------------------
> 
> Now we provide a module that uses the interface, but does not reveal the implementation.  The implementation is provided to the using module using a configuration file, Platform, similar to that used in NewSpeak.  It would tell the module where to find the missing definition of stackMaker that is declared, but not defined, in the interface module.
>  
> -------------------------------------------------------------- 
>  
> StackUsingModule:
>  
> from StackInterfaceModule import Stack<T>, StackFactory, stackMaker
>        using Platform.StackMaker  
> // "using" notation allows linker to find implementation of stackMaker from Platform
>  
> def myStack: Stack<Number> = stackMaker.empty
> …  // omitted code that uses myStack
>  
> end StackUsingModule
>  
> -------------------------------------------------------------- 
>  
> The next module will use the class in the implementation module to write an extension to stackClass.  Think of it as being written by a tool-builder rather than a client of the original interface. It extends stackClass by importing information from the StackImplementationModule (some of it obtained transitively from the interface module) and then defining the subclass.
>  
>  -------------------------------------------------------------- 
>  
> StackModifyingModule:
>  
> from StackImplementationModule import Stack<T>, StackFactory, stackMaker, StackClass
> // if no transitive export than might need instead to import some from StackInterfaceModule
>  
> type CountingStack<T> extends Stack<T> {  // minor modification to Stack
>       count -> Number
> }
>  
> class CountingStackClass<T> implements CountingStack<T> {
>            extends StackClass<T>.new
>        var count:= 0;
>        override method push ….
>> }
>  
> end StackModifyingModule
>  
> --------------------------------------------------------------
>  
> In this design, I did not draw a strict distinction between implementation and interface modules.  That might make it easier to adapt these to the dynamic typing world, but I’m not sure.  I do think it is important to have modules that can provide just specification material without the actual implementations of objects, classes, etc.
>  
> With this design, a module is simply a group of declarations and definitions of types, objects, and classes kept in a single file.  We could add keywords to indicate the beginning and ending of modules, or we could try to wrap them all in a single type or objects, but that seems less comfortable to me.
>  
> At this point I don’t see a need to have parameterized modules, as we can parameterize their contents, but there would be no difficulty in parameterizing the modules themselves.
>  
> I personally would love to put in “partial revelations”, as in Modula-3, which provide partial information about the types exported by a module, but have left that out for simplicity.
>  
> The Platform configuration file plays a major role here of connecting declarations to missing definitions.  My understanding is that this works reasonably well in NewSpeak, and so hopefully would work just as well in Grace.  The idea is that it locates in a single place the connections between modules that you would not like have to be hard-wired into code.  E.g., you don’t want to have to change a large chunk of your code (even in minor ways) if you change from an array-based stack implementation to one using linked lists.  Instead, you should be able to make a change in the Platform object/file and have the changes percolate through the code.
>  
>  
> _______________________________________________
> Grace-core mailing list
> Grace-core at cecs.pdx.edu
> https://mailhost.cecs.pdx.edu/mailman/listinfo/grace-core



More information about the Grace-core mailing list